From 95276127e373f2e2fb2a208ff77267422a197d9f Mon Sep 17 00:00:00 2001 From: xgu3 Date: Thu, 5 Jul 2007 07:05:28 +0000 Subject: Check in following modules, DxeIpl ConPlatform ConSplitter GraphicsConsole Terminal DevicePath git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3069 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Console/ConSplitterDxe/CommonHeader.h | 61 + .../Console/ConSplitterDxe/ComponentName.c | 485 +++ .../Universal/Console/ConSplitterDxe/ConSplitter.c | 3467 ++++++++++++++++++++ .../Universal/Console/ConSplitterDxe/ConSplitter.h | 667 ++++ .../Console/ConSplitterDxe/ConSplitter.inf | 120 + .../Console/ConSplitterDxe/ConSplitter.msa | 126 + .../Console/ConSplitterDxe/ConSplitterGraphics.c | 1222 +++++++ 7 files changed, 6148 insertions(+) create mode 100644 MdeModulePkg/Universal/Console/ConSplitterDxe/CommonHeader.h create mode 100644 MdeModulePkg/Universal/Console/ConSplitterDxe/ComponentName.c create mode 100644 MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c create mode 100644 MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.h create mode 100644 MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.inf create mode 100644 MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.msa create mode 100644 MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterGraphics.c (limited to 'MdeModulePkg/Universal/Console/ConSplitterDxe') diff --git a/MdeModulePkg/Universal/Console/ConSplitterDxe/CommonHeader.h b/MdeModulePkg/Universal/Console/ConSplitterDxe/CommonHeader.h new file mode 100644 index 0000000000..7feaec4161 --- /dev/null +++ b/MdeModulePkg/Universal/Console/ConSplitterDxe/CommonHeader.h @@ -0,0 +1,61 @@ +/**@file + Common header file shared by all source files. + + This file includes package header files, library classes and protocol, PPI & GUID definitions. + + Copyright (c) 2006 - 2007, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#ifndef __COMMON_HEADER_H_ +#define __COMMON_HEADER_H_ + + +// +// The package level header files this module uses +// +#include +// +// The protocols, PPI and GUID defintions for this module +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// +// The Library classes this module consumes +// +#include +#include +#include +#include +#include +#include +#include +// +// Driver Binding Externs +// +extern EFI_DRIVER_BINDING_PROTOCOL gConSplitterConInDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gConSplitterConInComponentName; +extern EFI_DRIVER_BINDING_PROTOCOL gConSplitterSimplePointerDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gConSplitterSimplePointerComponentName; +extern EFI_DRIVER_BINDING_PROTOCOL gConSplitterConOutDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gConSplitterConOutComponentName; +extern EFI_DRIVER_BINDING_PROTOCOL gConSplitterStdErrDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gConSplitterStdErrComponentName; + + +#endif diff --git a/MdeModulePkg/Universal/Console/ConSplitterDxe/ComponentName.c b/MdeModulePkg/Universal/Console/ConSplitterDxe/ComponentName.c new file mode 100644 index 0000000000..6d1bf15a21 --- /dev/null +++ b/MdeModulePkg/Universal/Console/ConSplitterDxe/ComponentName.c @@ -0,0 +1,485 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#include "ConSplitter.h" + +// +// EFI Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gConSplitterConInComponentName = { + ConSplitterComponentNameGetDriverName, + ConSplitterConInComponentNameGetControllerName, + "eng" +}; + +EFI_COMPONENT_NAME_PROTOCOL gConSplitterSimplePointerComponentName = { + ConSplitterComponentNameGetDriverName, + ConSplitterSimplePointerComponentNameGetControllerName, + "eng" +}; + +EFI_COMPONENT_NAME_PROTOCOL gConSplitterConOutComponentName = { + ConSplitterComponentNameGetDriverName, + ConSplitterConOutComponentNameGetControllerName, + "eng" +}; + +EFI_COMPONENT_NAME_PROTOCOL gConSplitterStdErrComponentName = { + ConSplitterComponentNameGetDriverName, + ConSplitterStdErrComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mConSplitterDriverNameTable[] = { + { + "eng", + (CHAR16 *) L"Console Splitter Driver" + }, + { + NULL, + NULL + } +}; + +static EFI_UNICODE_STRING_TABLE mConSplitterConInControllerNameTable[] = { + { + "eng", + (CHAR16 *) L"Primary Console Input Device" + }, + { + NULL, + NULL + } +}; + +static EFI_UNICODE_STRING_TABLE mConSplitterSimplePointerControllerNameTable[] = { + { + "eng", + (CHAR16 *) L"Primary Simple Pointer Device" + }, + { + NULL, + NULL + } +}; + +static EFI_UNICODE_STRING_TABLE mConSplitterConOutControllerNameTable[] = { + { + "eng", + (CHAR16 *) L"Primary Console Output Device" + }, + { + NULL, + NULL + } +}; + +static EFI_UNICODE_STRING_TABLE mConSplitterStdErrControllerNameTable[] = { + { + "eng", + (CHAR16 *) L"Primary Standard Error Device" + }, + { + NULL, + NULL + } +}; + +EFI_STATUS +EFIAPI +ConSplitterComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + Language - A pointer to a three character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + DriverName - A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gConSplitterConInComponentName.SupportedLanguages, + mConSplitterDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +ConSplitterConInComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + ControllerHandle - The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + ChildHandle - The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + Language - A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + ControllerName - A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language + specified by Language from the point of view of the + driver specified by This. + + Returns: + EFI_SUCCESS - The Unicode string for the user readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn; + // + // here ChildHandle is not an Optional parameter. + // + if (ChildHandle == NULL) { + return EFI_UNSUPPORTED; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimpleTextInProtocolGuid, + (VOID **) &TextIn, + NULL, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + return LookupUnicodeString ( + Language, + gConSplitterConInComponentName.SupportedLanguages, + mConSplitterConInControllerNameTable, + ControllerName + ); +} + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + ControllerHandle - The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + ChildHandle - The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + Language - A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + ControllerName - A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language + specified by Language from the point of view of the + driver specified by This. + + Returns: + EFI_SUCCESS - The Unicode string for the user readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer; + // + // here ChildHandle is not an Optional parameter. + // + if (ChildHandle == NULL) { + return EFI_UNSUPPORTED; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimplePointerProtocolGuid, + (VOID **) &SimplePointer, + NULL, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + return LookupUnicodeString ( + Language, + gConSplitterSimplePointerComponentName.SupportedLanguages, + mConSplitterSimplePointerControllerNameTable, + ControllerName + ); +} + +EFI_STATUS +EFIAPI +ConSplitterConOutComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + ControllerHandle - The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + ChildHandle - The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + Language - A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + ControllerName - A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language + specified by Language from the point of view of the + driver specified by This. + + Returns: + EFI_SUCCESS - The Unicode string for the user readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; + // + // here ChildHandle is not an Optional parameter. + // + if (ChildHandle == NULL) { + return EFI_UNSUPPORTED; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimpleTextOutProtocolGuid, + (VOID **) &TextOut, + NULL, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + return LookupUnicodeString ( + Language, + gConSplitterConOutComponentName.SupportedLanguages, + mConSplitterConOutControllerNameTable, + ControllerName + ); +} + +EFI_STATUS +EFIAPI +ConSplitterStdErrComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + ControllerHandle - The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + ChildHandle - The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + Language - A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + ControllerName - A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language + specified by Language from the point of view of the + driver specified by This. + + Returns: + EFI_SUCCESS - The Unicode string for the user readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ErrOut; + // + // here ChildHandle is not an Optional parameter. + // + if (ChildHandle == NULL) { + return EFI_UNSUPPORTED; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimpleTextOutProtocolGuid, + (VOID **) &ErrOut, + NULL, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + return LookupUnicodeString ( + Language, + gConSplitterStdErrComponentName.SupportedLanguages, + mConSplitterStdErrControllerNameTable, + ControllerName + ); +} diff --git a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c new file mode 100644 index 0000000000..ead6d654d8 --- /dev/null +++ b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c @@ -0,0 +1,3467 @@ +/**@file + Console Splitter Driver. Any Handle that attatched + EFI_CONSOLE_IDENTIFIER_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. + EFI_CONSOLE_SPLIT_PROTOCOL will be attatched onto each virtual handle to + identify the splitter type. + + Each virtual handle, that supports both the EFI_CONSOLE_SPLIT_PROTOCOL + and 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 - 2007 Intel Corporation.
+All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#include "ConSplitter.h" + +// +// Global Variables +// +STATIC 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, + + { + ConSplitterSimplePointerReset, + ConSplitterSimplePointerGetState, + (EFI_EVENT) NULL, + (EFI_SIMPLE_POINTER_MODE *) NULL + }, + { + 0x10000, + 0x10000, + 0x10000, + TRUE, + TRUE + }, + 0, + (EFI_SIMPLE_POINTER_PROTOCOL **) NULL, + 0, + + FALSE, + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + 0, + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + (EFI_EVENT) NULL, + + FALSE, + FALSE +}; + +STATIC 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, + }, + { + ConSpliterGraphicsOutputQueryMode, + ConSpliterGraphicsOutputSetMode, + ConSpliterGraphicsOutputBlt, + NULL + }, + (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) NULL, + (TEXT_OUT_GOP_MODE *) NULL, + 0, + TRUE, + { + ConSpliterConsoleControlGetMode, + ConSpliterConsoleControlSetMode, + ConSpliterConsoleControlLockStdIn + }, + + 0, + (TEXT_OUT_AND_GOP_DATA *) NULL, + 0, + (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL, + 0, + (INT32 *) NULL, + + EfiConsoleControlScreenText, + 0, + 0, + (CHAR16 *) NULL, + (INT32 *) NULL +}; + +STATIC 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, + }, + { + ConSpliterGraphicsOutputQueryMode, + ConSpliterGraphicsOutputSetMode, + ConSpliterGraphicsOutputBlt, + NULL + }, + (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) NULL, + (TEXT_OUT_GOP_MODE *) NULL, + 0, + TRUE, + { + ConSpliterConsoleControlGetMode, + ConSpliterConsoleControlSetMode, + ConSpliterConsoleControlLockStdIn + }, + + 0, + (TEXT_OUT_AND_GOP_DATA *) NULL, + 0, + (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL, + 0, + (INT32 *) NULL, + + EfiConsoleControlScreenText, + 0, + 0, + (CHAR16 *) NULL, + (INT32 *) NULL +}; + +EFI_DRIVER_BINDING_PROTOCOL gConSplitterConInDriverBinding = { + ConSplitterConInDriverBindingSupported, + ConSplitterConInDriverBindingStart, + ConSplitterConInDriverBindingStop, + 0xa, + NULL, + NULL +}; + +EFI_DRIVER_BINDING_PROTOCOL gConSplitterSimplePointerDriverBinding = { + ConSplitterSimplePointerDriverBindingSupported, + ConSplitterSimplePointerDriverBindingStart, + ConSplitterSimplePointerDriverBindingStop, + 0xa, + NULL, + NULL +}; + +EFI_DRIVER_BINDING_PROTOCOL gConSplitterConOutDriverBinding = { + ConSplitterConOutDriverBindingSupported, + ConSplitterConOutDriverBindingStart, + ConSplitterConOutDriverBindingStop, + 0xa, + NULL, + NULL +}; + +EFI_DRIVER_BINDING_PROTOCOL gConSplitterStdErrDriverBinding = { + ConSplitterStdErrDriverBindingSupported, + ConSplitterStdErrDriverBindingStart, + ConSplitterStdErrDriverBindingStop, + 0xa, + NULL, + NULL +}; + +/** + The user Entry Point for module ConSplitter. The user code starts with this function. + + @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 +InitializeConSplitter( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Install driver model protocol(s). + // + Status = EfiLibInstallAllDriverProtocols ( + ImageHandle, + SystemTable, + &gConSplitterConInDriverBinding, + ImageHandle, + &gConSplitterConInComponentName, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + Status = EfiLibInstallAllDriverProtocols ( + ImageHandle, + SystemTable, + &gConSplitterSimplePointerDriverBinding, + NULL, + &gConSplitterSimplePointerComponentName, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + Status = EfiLibInstallAllDriverProtocols ( + ImageHandle, + SystemTable, + &gConSplitterConOutDriverBinding, + NULL, + &gConSplitterConOutComponentName, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + Status = EfiLibInstallAllDriverProtocols ( + ImageHandle, + SystemTable, + &gConSplitterStdErrDriverBinding, + NULL, + &gConSplitterStdErrComponentName, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + + // + // Call the original Entry Point + // + Status = ConSplitterDriverEntry (ImageHandle, SystemTable); + + return Status; +} + + +EFI_STATUS +EFIAPI +ConSplitterDriverEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Intialize a virtual console device to act as an agrigator of physical console + devices. + +Arguments: + ImageHandle - (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT) + SystemTable - (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT) +Returns: + EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + + // + // The driver creates virtual handles for ConIn, ConOut, and 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 StdErr Splitter + // + Status = ConSplitterTextOutConstructor (&mStdErr); + if (!EFI_ERROR (Status)) { + Status = gBS->InstallMultipleProtocolInterfaces ( + &mStdErr.VirtualHandle, + &gEfiSimpleTextOutProtocolGuid, + &mStdErr.TextOut, + &gEfiPrimaryStandardErrorDeviceGuid, + NULL, + NULL + ); + } + // + // Create virtual device handle for ConIn Splitter + // + Status = ConSplitterTextInConstructor (&mConIn); + if (!EFI_ERROR (Status)) { + Status = gBS->InstallMultipleProtocolInterfaces ( + &mConIn.VirtualHandle, + &gEfiSimpleTextInProtocolGuid, + &mConIn.TextIn, + &gEfiSimplePointerProtocolGuid, + &mConIn.SimplePointer, + &gEfiPrimaryConsoleInDeviceGuid, + NULL, + NULL + ); + if (!EFI_ERROR (Status)) { + // + // Update the EFI System Table with new virtual console + // + gST->ConsoleInHandle = mConIn.VirtualHandle; + gST->ConIn = &mConIn.TextIn; + } + } + // + // Create virtual device handle for ConOut Splitter + // + Status = ConSplitterTextOutConstructor (&mConOut); + if (!EFI_ERROR (Status)) { + // + // In UEFI mode, Graphics Output Protocol is installed on virtual handle. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mConOut.VirtualHandle, + &gEfiSimpleTextOutProtocolGuid, + &mConOut.TextOut, + &gEfiGraphicsOutputProtocolGuid, + &mConOut.GraphicsOutput, + &gEfiConsoleControlProtocolGuid, + &mConOut.ConsoleControl, + &gEfiPrimaryConsoleOutDeviceGuid, + NULL, + NULL + ); + + if (!EFI_ERROR (Status)) { + // + // Update the EFI System Table with new virtual console + // + gST->ConsoleOutHandle = mConOut.VirtualHandle; + gST->ConOut = &mConOut.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; +} + +EFI_STATUS +ConSplitterTextInConstructor ( + TEXT_IN_SPLITTER_PRIVATE_DATA *ConInPrivate + ) +/*++ + +Routine Description: + + Construct the ConSplitter. + +Arguments: + + ConInPrivate - A pointer to the TEXT_IN_SPLITTER_PRIVATE_DATA structure. + +Returns: + EFI_OUT_OF_RESOURCES - Out of resources. + +--*/ +{ + EFI_STATUS Status; + + // + // Initilize console input splitter's private data. + // + 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 support locking StdIn Device + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + ConSpliterConsoleControlLockStdInEvent, + NULL, + &ConInPrivate->LockEvent + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->CreateEvent ( + EVT_NOTIFY_WAIT, + TPL_NOTIFY, + ConSplitterTextInWaitForKey, + ConInPrivate, + &ConInPrivate->TextIn.WaitForKey + ); + ASSERT_EFI_ERROR (Status); + + ConInPrivate->SimplePointer.Mode = &ConInPrivate->SimplePointerMode; + + Status = ConSplitterGrowBuffer ( + sizeof (EFI_SIMPLE_POINTER_PROTOCOL *), + &ConInPrivate->PointerListCount, + (VOID **) &ConInPrivate->PointerList + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + Status = gBS->CreateEvent ( + EVT_NOTIFY_WAIT, + TPL_NOTIFY, + ConSplitterSimplePointerWaitForInput, + ConInPrivate, + &ConInPrivate->SimplePointer.WaitForInput + ); + + return Status; +} + +EFI_STATUS +ConSplitterTextOutConstructor ( + TEXT_OUT_SPLITTER_PRIVATE_DATA *ConOutPrivate + ) +{ + EFI_STATUS Status; + + // + // Initilize console output splitter's private data. + // + ConOutPrivate->TextOut.Mode = &ConOutPrivate->TextOutMode; + + Status = ConSplitterGrowBuffer ( + sizeof (TEXT_OUT_AND_GOP_DATA), + &ConOutPrivate->TextOutListCount, + (VOID **) &ConOutPrivate->TextOutList + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + Status = ConSplitterGrowBuffer ( + sizeof (TEXT_OUT_SPLITTER_QUERY_DATA), + &ConOutPrivate->TextOutQueryDataCount, + (VOID **) &ConOutPrivate->TextOutQueryData + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + // + // Setup the DevNullTextOut console to 80 x 25 + // + ConOutPrivate->TextOutQueryData[0].Columns = 80; + ConOutPrivate->TextOutQueryData[0].Rows = 25; + DevNullTextOutSetMode (ConOutPrivate, 0); + + // + // 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 + // + if ((ConOutPrivate->GraphicsOutputModeBuffer = AllocateZeroPool (sizeof (TEXT_OUT_GOP_MODE))) == NULL) { + return EFI_OUT_OF_RESOURCES; + } + ConOutPrivate->GraphicsOutputModeBuffer[0].HorizontalResolution = 800; + ConOutPrivate->GraphicsOutputModeBuffer[0].VerticalResolution = 600; + + // + // Initialize the following items, theset items remain unchanged in GraphicsOutput->SetMode() + // GraphicsOutputMode->Info->Version, GraphicsOutputMode->Info->PixelFormat + // GraphicsOutputMode->SizeOfInfo, GraphicsOutputMode->FrameBufferBase, GraphicsOutputMode->FrameBufferSize + // + ConOutPrivate->GraphicsOutput.Mode->Info->Version = 0; + ConOutPrivate->GraphicsOutput.Mode->Info->PixelFormat = PixelBltOnly; + ConOutPrivate->GraphicsOutput.Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); + ConOutPrivate->GraphicsOutput.Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) NULL; + ConOutPrivate->GraphicsOutput.Mode->FrameBufferSize = 0; + + ConOutPrivate->GraphicsOutput.Mode->MaxMode = 1; + // + // Initial current mode to unknow state, and then set to mode 0 + // + ConOutPrivate->GraphicsOutput.Mode->Mode = 0xffff; + ConOutPrivate->GraphicsOutput.SetMode (&ConOutPrivate->GraphicsOutput, 0); + + return Status; +} + +STATIC +EFI_STATUS +ConSplitterSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_GUID *Guid + ) +/*++ + +Routine Description: + Generic Supported Check + +Arguments: + This - Pointer to protocol. + ControllerHandle - Controller Handle. + Guid - Guid. + +Returns: + + EFI_UNSUPPORTED - unsupported. + EFI_SUCCESS - operation is OK. + +--*/ +{ + EFI_STATUS Status; + VOID *Instance; + + // + // Make sure the Console Splitter does not attempt to attach to itself + // + if (ControllerHandle == mConIn.VirtualHandle) { + return EFI_UNSUPPORTED; + } + + if (ControllerHandle == mConOut.VirtualHandle) { + return EFI_UNSUPPORTED; + } + + if (ControllerHandle == mStdErr.VirtualHandle) { + return EFI_UNSUPPORTED; + } + // + // Check to see whether the handle has the ConsoleInDevice GUID on it + // + 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; +} + +EFI_STATUS +EFIAPI +ConSplitterConInDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Console In Supported Check + +Arguments: + This - Pointer to protocol. + ControllerHandle - Controller handle. + RemainingDevicePath - Remaining device path. + +Returns: + + EFI_STATUS + +--*/ +{ + return ConSplitterSupported ( + This, + ControllerHandle, + &gEfiConsoleInDeviceGuid + ); +} + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Standard Error Supported Check + +Arguments: + This - Pointer to protocol. + ControllerHandle - Controller handle. + RemainingDevicePath - Remaining device path. + +Returns: + + EFI_STATUS + +--*/ +{ + return ConSplitterSupported ( + This, + ControllerHandle, + &gEfiSimplePointerProtocolGuid + ); +} + +EFI_STATUS +EFIAPI +ConSplitterConOutDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Console Out Supported Check + +Arguments: + This - Pointer to protocol. + ControllerHandle - Controller handle. + RemainingDevicePath - Remaining device path. + +Returns: + + EFI_STATUS + +--*/ +{ + return ConSplitterSupported ( + This, + ControllerHandle, + &gEfiConsoleOutDeviceGuid + ); +} + +EFI_STATUS +EFIAPI +ConSplitterStdErrDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Standard Error Supported Check + +Arguments: + This - Pointer to protocol. + ControllerHandle - Controller handle. + RemainingDevicePath - Remaining device path. + +Returns: + + EFI_STATUS + +--*/ +{ + return ConSplitterSupported ( + This, + ControllerHandle, + &gEfiStandardErrorDeviceGuid + ); +} + +STATIC +EFI_STATUS +EFIAPI +ConSplitterStart ( + 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 + ) +/*++ + +Routine Description: + Start ConSplitter on ControllerHandle, and create the virtual + agrogated console device on first call Start for a SimpleTextIn handle. + +Arguments: + (Standard DriverBinding Protocol Start() function) + +Returns: + EFI_ERROR if a SimpleTextIn protocol is not started. + +--*/ +{ + EFI_STATUS Status; + VOID *Instance; + + // + // Check to see whether the handle has the ConsoleInDevice GUID on it + // + Status = gBS->OpenProtocol ( + ControllerHandle, + DeviceGuid, + &Instance, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + DeviceGuid, + &Instance, + This->DriverBindingHandle, + ConSplitterVirtualHandle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return gBS->OpenProtocol ( + ControllerHandle, + InterfaceGuid, + Interface, + This->DriverBindingHandle, + ConSplitterVirtualHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); +} + +EFI_STATUS +EFIAPI +ConSplitterConInDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Start ConSplitter on ControllerHandle, and create the virtual + agrogated console device on first call Start for a SimpleTextIn handle. + +Arguments: + This - Pointer to protocol. + ControllerHandle - Controller handle. + RemainingDevicePath - Remaining device path. + +Returns: + + EFI_STATUS + EFI_ERROR if a SimpleTextIn protocol is not started. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn; + + // + // 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; + } + + return ConSplitterTextInAddDevice (&mConIn, TextIn); +} + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Start ConSplitter on ControllerHandle, and create the virtual + agrogated console device on first call Start for a SimpleTextIn handle. + +Arguments: + This - Pointer to protocol. + ControllerHandle - Controller handle. + RemainingDevicePath - Remaining device path. + +Returns: + + EFI_ERROR if a SimpleTextIn protocol is not started. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer; + + Status = ConSplitterStart ( + This, + ControllerHandle, + mConIn.VirtualHandle, + &gEfiSimplePointerProtocolGuid, + &gEfiSimplePointerProtocolGuid, + (VOID **) &SimplePointer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return ConSplitterSimplePointerAddDevice (&mConIn, SimplePointer); +} + +EFI_STATUS +EFIAPI +ConSplitterConOutDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Start ConSplitter on ControllerHandle, and create the virtual + agrogated console device on first call Start for a SimpleTextIn handle. + +Arguments: + This - Pointer to protocol. + ControllerHandle - Controller handle. + RemainingDevicePath - Remaining device path. + +Returns: + EFI_ERROR if a SimpleTextIn protocol is not started. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + + Status = ConSplitterStart ( + This, + ControllerHandle, + mConOut.VirtualHandle, + &gEfiConsoleOutDeviceGuid, + &gEfiSimpleTextOutProtocolGuid, + (VOID **) &TextOut + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // 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)) { + GraphicsOutput = NULL; + } + // + // Open UGA_DRAW protocol + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUgaDrawProtocolGuid, + (VOID **) &UgaDraw, + This->DriverBindingHandle, + mConOut.VirtualHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + UgaDraw = NULL; + } + // + // 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)); + + return Status; +} + +EFI_STATUS +EFIAPI +ConSplitterStdErrDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Start ConSplitter on ControllerHandle, and create the virtual + agrogated console device on first call Start for a SimpleTextIn handle. + +Arguments: + This - Pointer to protocol. + ControllerHandle - Controller handle. + RemainingDevicePath - Remaining device path. + +Returns: + EFI_ERROR if a SimpleTextIn protocol is not started. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; + + Status = ConSplitterStart ( + This, + ControllerHandle, + mStdErr.VirtualHandle, + &gEfiStandardErrorDeviceGuid, + &gEfiSimpleTextOutProtocolGuid, + (VOID **) &TextOut + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // 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; + } + + if (mStdErr.CurrentNumberOfConsoles == 1) { + gST->StandardErrorHandle = mStdErr.VirtualHandle; + gST->StdErr = &mStdErr.TextOut; + // + // Update the CRC32 in the EFI System Table header + // + gST->Hdr.CRC32 = 0; + gBS->CalculateCrc32 ( + (UINT8 *) &gST->Hdr, + gST->Hdr.HeaderSize, + &gST->Hdr.CRC32 + ); + } + + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +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 + ) +/*++ + +Routine Description: + +Arguments: + (Standard DriverBinding Protocol Stop() function) + +Returns: + + None + +--*/ +{ + 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; +} + +EFI_STATUS +EFIAPI +ConSplitterConInDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + +Arguments: + (Standard DriverBinding Protocol Stop() function) + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn; + + if (NumberOfChildren == 0) { + return EFI_SUCCESS; + } + + Status = ConSplitterStop ( + This, + ControllerHandle, + mConIn.VirtualHandle, + &gEfiConsoleInDeviceGuid, + &gEfiSimpleTextInProtocolGuid, + (VOID **) &TextIn + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Delete this console input device's data structures. + // + return ConSplitterTextInDeleteDevice (&mConIn, TextIn); +} + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + +Arguments: + (Standard DriverBinding Protocol Stop() function) + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer; + + if (NumberOfChildren == 0) { + return EFI_SUCCESS; + } + + Status = ConSplitterStop ( + This, + ControllerHandle, + mConIn.VirtualHandle, + &gEfiSimplePointerProtocolGuid, + &gEfiSimplePointerProtocolGuid, + (VOID **) &SimplePointer + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Delete this console input device's data structures. + // + return ConSplitterSimplePointerDeleteDevice (&mConIn, SimplePointer); +} + +EFI_STATUS +EFIAPI +ConSplitterConOutDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + +Arguments: + (Standard DriverBinding Protocol Stop() function) + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; + + if (NumberOfChildren == 0) { + return EFI_SUCCESS; + } + + Status = ConSplitterStop ( + This, + ControllerHandle, + mConOut.VirtualHandle, + &gEfiConsoleOutDeviceGuid, + &gEfiSimpleTextOutProtocolGuid, + (VOID **) &TextOut + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Delete this console output device's data structures. + // + return ConSplitterTextOutDeleteDevice (&mConOut, TextOut); +} + +EFI_STATUS +EFIAPI +ConSplitterStdErrDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + +Arguments: + (Standard DriverBinding Protocol Stop() function) + +Returns: + + EFI_SUCCESS - Complete successfully. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; + + if (NumberOfChildren == 0) { + return EFI_SUCCESS; + } + + 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. + // + Status = ConSplitterTextOutDeleteDevice (&mStdErr, TextOut); + if (EFI_ERROR (Status)) { + return Status; + } + + if (mStdErr.CurrentNumberOfConsoles == 0) { + gST->StandardErrorHandle = NULL; + gST->StdErr = NULL; + // + // Update the CRC32 in the EFI System Table header + // + gST->Hdr.CRC32 = 0; + gBS->CalculateCrc32 ( + (UINT8 *) &gST->Hdr, + gST->Hdr.HeaderSize, + &gST->Hdr.CRC32 + ); + } + + return Status; +} + +EFI_STATUS +ConSplitterGrowBuffer ( + IN UINTN SizeOfCount, + IN UINTN *Count, + IN OUT VOID **Buffer + ) +/*++ + +Routine Description: + Take the passed in Buffer of size SizeOfCount and grow the buffer + by MAX (CONSOLE_SPLITTER_CONSOLES_ALLOC_UNIT, MaxGrow) * SizeOfCount + bytes. Copy the current data in Buffer to the new version of Buffer + and free the old version of buffer. + + +Arguments: + SizeOfCount - Size of element in array + Count - Current number of elements in array + Buffer - Bigger version of passed in Buffer with all the data + +Returns: + EFI_SUCCESS - Buffer size has grown + EFI_OUT_OF_RESOURCES - Could not grow the buffer size + + None + +--*/ +{ + UINTN NewSize; + UINTN OldSize; + 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. + // + OldSize = *Count * SizeOfCount; + *Count += CONSOLE_SPLITTER_CONSOLES_ALLOC_UNIT; + NewSize = *Count * SizeOfCount; + + Ptr = AllocateZeroPool (NewSize); + if (Ptr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (Ptr, *Buffer, OldSize); + + if (*Buffer != NULL) { + FreePool (*Buffer); + } + + *Buffer = Ptr; + + return EFI_SUCCESS; +} + +EFI_STATUS +ConSplitterTextInAddDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + EFI_SUCCESS + EFI_OUT_OF_RESOURCES + +--*/ +{ + EFI_STATUS Status; + + // + // If the Text In List is full, enlarge it by calling growbuffer(). + // + 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() in UI.c + // + gBS->CheckEvent (TextIn->WaitForKey); + + return EFI_SUCCESS; +} + +EFI_STATUS +ConSplitterTextInDeleteDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + EFI_SUCCESS + EFI_NOT_FOUND + +--*/ +{ + 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 = Index; Index < Private->CurrentNumberOfConsoles - 1; Index++) { + Private->TextInList[Index] = Private->TextInList[Index + 1]; + } + + Private->CurrentNumberOfConsoles--; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +ConSplitterSimplePointerAddDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + EFI_OUT_OF_RESOURCES + EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + + // + // If the Text In List is full, enlarge it by calling growbuffer(). + // + 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 Text In List. + // + Private->PointerList[Private->CurrentNumberOfPointers] = SimplePointer; + Private->CurrentNumberOfPointers++; + return EFI_SUCCESS; +} + +EFI_STATUS +ConSplitterSimplePointerDeleteDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + 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->CurrentNumberOfPointers; Index++) { + if (Private->PointerList[Index] == SimplePointer) { + for (Index = Index; Index < Private->CurrentNumberOfPointers - 1; Index++) { + Private->PointerList[Index] = Private->PointerList[Index + 1]; + } + + Private->CurrentNumberOfPointers--; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +STATIC +EFI_STATUS +ConSplitterGrowMapTable ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + UINTN Size; + UINTN NewSize; + UINTN TotalSize; + INT32 *TextOutModeMap; + INT32 *OldTextOutModeMap; + INT32 *SrcAddress; + INT32 Index; + + NewSize = Private->TextOutListCount * sizeof (INT32); + OldTextOutModeMap = Private->TextOutModeMap; + TotalSize = NewSize * Private->TextOutQueryDataCount; + + TextOutModeMap = AllocateZeroPool (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; + + // + // Copy the old data to the new one + // + while (Index < Private->TextOutMode.MaxMode) { + CopyMem (TextOutModeMap, SrcAddress, Size); + TextOutModeMap += NewSize; + SrcAddress += Size; + Index++; + } + // + // Free the old buffer + // + FreePool (OldTextOutModeMap); + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ConSplitterAddOutputMode ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + 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) { + TextOut->QueryMode ( + TextOut, + Mode, + &Private->TextOutQueryData[Mode].Columns, + &Private->TextOutQueryData[Mode].Rows + ); + Private->TextOutModeMap[Index] = Mode; + Mode++; + Index += Private->TextOutListCount; + } + + return EFI_SUCCESS; +} + +STATIC +VOID +ConSplitterGetIntersection ( + IN INT32 *TextOutModeMap, + IN INT32 *NewlyAddedMap, + IN UINTN MapStepSize, + IN UINTN NewMapStepSize, + OUT INT32 *MaxMode, + OUT INT32 *CurrentMode + ) +{ + INT32 Index; + INT32 *CurrentMapEntry; + INT32 *NextMapEntry; + INT32 CurrentMaxMode; + INT32 Mode; + + Index = 0; + CurrentMapEntry = TextOutModeMap; + NextMapEntry = TextOutModeMap; + CurrentMaxMode = *MaxMode; + Mode = *CurrentMode; + + while (Index < CurrentMaxMode) { + if (*NewlyAddedMap == -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; + NewlyAddedMap += NewMapStepSize; + Index++; + } + + *CurrentMode = Mode; + + return ; +} + +STATIC +VOID +ConSplitterSyncOutputMode ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut + ) +/*++ + +Routine Description: + +Arguments: + Private - Private data structure. + TextOut - Text Out Protocol. +Returns: + + None + +--*/ +{ + INT32 CurrentMaxMode; + INT32 Mode; + INT32 Index; + INT32 *TextOutModeMap; + INT32 *MapTable; + TEXT_OUT_SPLITTER_QUERY_DATA *TextOutQueryData; + UINTN Rows; + UINTN Columns; + UINTN StepSize; + + // + // 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) { + TextOut->QueryMode (TextOut, Mode, &Columns, &Rows); + + // + // Search the QueryData database to see if they intersects + // + Index = 0; + while (Index < CurrentMaxMode) { + if ((TextOutQueryData[Index].Rows == Rows) && (TextOutQueryData[Index].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 ; +} + +STATIC +EFI_STATUS +ConSplitterGetIntersectionBetweenConOutAndStrErr ( + VOID + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + EFI_OUT_OF_RESOURCES + +--*/ +{ + UINTN ConOutNumOfConsoles; + UINTN StdErrNumOfConsoles; + TEXT_OUT_AND_GOP_DATA *ConOutTextOutList; + TEXT_OUT_AND_GOP_DATA *StdErrTextOutList; + UINTN Indexi; + UINTN Indexj; + UINTN Rows; + UINTN Columns; + INT32 ConOutMaxMode; + INT32 StdErrMaxMode; + INT32 Mode; + INT32 Index; + INT32 *ConOutModeMap; + INT32 *StdErrModeMap; + INT32 *ConOutMapTable; + INT32 *StdErrMapTable; + TEXT_OUT_SPLITTER_QUERY_DATA *ConOutQueryData; + TEXT_OUT_SPLITTER_QUERY_DATA *StdErrQueryData; + 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; + ConOutQueryData = mConOut.TextOutQueryData; + + StdErrMaxMode = mStdErr.TextOutMode.MaxMode; + StdErrModeMap = mStdErr.TextOutModeMap; + 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 other's QueryData database to see if they intersect + // + Index = 0; + Rows = ConOutQueryData[Mode].Rows; + Columns = ConOutQueryData[Mode].Columns; + while (Index < StdErrMaxMode) { + if ((StdErrQueryData[Index].Rows == Rows) && (StdErrQueryData[Index].Columns == Columns)) { + 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; +} + +STATIC +EFI_STATUS +ConSplitterAddGraphicsOutputMode ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput, + IN EFI_UGA_DRAW_PROTOCOL *UgaDraw + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + UINTN Index; + TEXT_OUT_GOP_MODE *Mode; + UINTN SizeOfInfo; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; + EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *CurrentGraphicsOutputMode; + TEXT_OUT_GOP_MODE *ModeBuffer; + TEXT_OUT_GOP_MODE *MatchedMode; + UINTN NumberIndex; + BOOLEAN Match; + + if ((GraphicsOutput == NULL) && (UgaDraw == NULL)) { + return EFI_UNSUPPORTED; + } + + CurrentGraphicsOutputMode = Private->GraphicsOutput.Mode; + + 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 (TEXT_OUT_GOP_MODE) * 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++) { + Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) Index, &SizeOfInfo, &Info); + if (EFI_ERROR (Status)) { + return Status; + } + Mode->HorizontalResolution = Info->HorizontalResolution; + Mode->VerticalResolution = Info->VerticalResolution; + Mode++; + FreePool (Info); + } + } else { + // + // Check intersection of display mode + // + ModeBuffer = AllocatePool (sizeof (TEXT_OUT_GOP_MODE) * 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++) { + Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info); + if (EFI_ERROR (Status)) { + return Status; + } + if ((Info->HorizontalResolution == Mode->HorizontalResolution) && + (Info->VerticalResolution == Mode->VerticalResolution)){ + Match = TRUE; + FreePool (Info); + break; + } + FreePool (Info); + } + + if (Match) { + CopyMem (MatchedMode, Mode, sizeof (TEXT_OUT_GOP_MODE)); + 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 (TEXT_OUT_GOP_MODE)); + 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) NULL; + CurrentGraphicsOutputMode->FrameBufferSize = 0; + } + + // + // Select a prefered Display mode 800x600 + // + for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) { + Mode = &Private->GraphicsOutputModeBuffer[Index]; + if ((Mode->HorizontalResolution == 800) && (Mode->VerticalResolution == 600)) { + break; + } + } + // + // Prefered mode is not found, set to mode 0 + // + if (Index >= CurrentGraphicsOutputMode->MaxMode) { + Index = 0; + } + + // + // Current mode number may need update now, so set it to an invalide mode number + // + CurrentGraphicsOutputMode->Mode = 0xffff; + } else { + // + // For UGA device, it's inconvenient to retrieve all the supported display modes. + // To simplify the implementation, only add one resolution(800x600, 32bit color depth) as defined in UEFI spec + // + CurrentGraphicsOutputMode->MaxMode = 1; + CurrentGraphicsOutputMode->Info->Version = 0; + CurrentGraphicsOutputMode->Info->HorizontalResolution = 800; + CurrentGraphicsOutputMode->Info->VerticalResolution = 600; + CurrentGraphicsOutputMode->Info->PixelFormat = PixelBltOnly; + CurrentGraphicsOutputMode->Info->PixelsPerScanLine = 800; + CurrentGraphicsOutputMode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); + CurrentGraphicsOutputMode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) NULL; + CurrentGraphicsOutputMode->FrameBufferSize = 0; + + // + // Update the private mode buffer + // + ModeBuffer = &Private->GraphicsOutputModeBuffer[0]; + ModeBuffer->HorizontalResolution = 800; + ModeBuffer->VerticalResolution = 600; + + // + // Current mode is unknow now, set it to an invalid mode number 0xffff + // + CurrentGraphicsOutputMode->Mode = 0xffff; + Index = 0; + } + + // + // Force GraphicsOutput mode to be set, + // regardless whether the console is in EfiConsoleControlScreenGraphics or EfiConsoleControlScreenText mode + // + Private->HardwareNeedsStarting = TRUE; + Status = Private->GraphicsOutput.SetMode (&Private->GraphicsOutput, (UINT32) Index); + + Private->CurrentNumberOfGraphicsOutput++; + + return Status; +} + +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 + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + UINTN CurrentNumOfConsoles; + INT32 CurrentMode; + INT32 MaxMode; + TEXT_OUT_AND_GOP_DATA *TextAndGop; + + Status = EFI_SUCCESS; + CurrentNumOfConsoles = Private->CurrentNumberOfConsoles; + + // + // If the Text Out List is full, enlarge it by calling growbuffer(). + // + 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 ((GraphicsOutput == NULL) && (UgaDraw == NULL)) { + // + // If No UGA device then use the ConOut device + // + TextAndGop->TextOutEnabled = TRUE; + } else { + // + // If UGA device use ConOut device only used if UGA screen is in Text mode + // + TextAndGop->TextOutEnabled = (BOOLEAN) (Private->ConsoleOutputMode == EfiConsoleControlScreenText); + } + + 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 (); + + CurrentMode = Private->TextOutMode.Mode; + MaxMode = Private->TextOutMode.MaxMode; + ASSERT (MaxMode >= 1); + + if ((GraphicsOutput != NULL) || (UgaDraw != NULL)) { + ConSplitterAddGraphicsOutputMode (Private, GraphicsOutput, UgaDraw); + } + + if (Private->ConsoleOutputMode == EfiConsoleControlScreenGraphics && GraphicsOutput != NULL) { + // + // We just added a new UGA device in graphics mode + // + DevNullGopSync (Private, GraphicsOutput, UgaDraw); + } else if ((CurrentMode >= 0) && ((GraphicsOutput != NULL) || (UgaDraw != NULL)) && (CurrentMode < Private->TextOutMode.MaxMode)) { + // + // The new console supports the same mode of the current console so sync up + // + DevNullSyncGopStdOut (Private); + } else { + // + // If ConOut, then set the mode to Mode #0 which us 80 x 25 + // + Private->TextOut.SetMode (&Private->TextOut, 0); + } + + return Status; +} + +EFI_STATUS +ConSplitterTextOutDeleteDevice ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + 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) { + 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 (CurrentNumOfConsoles == 0) { + // + // If the number of consoles is zero clear the Dev NULL device + // + Private->CurrentNumberOfConsoles = 0; + Private->TextOutMode.MaxMode = 1; + Private->TextOutQueryData[0].Columns = 80; + Private->TextOutQueryData[0].Rows = 25; + DevNullTextOutSetMode (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; +} +// +// ConSplitter TextIn member functions +// +EFI_STATUS +EFIAPI +ConSplitterTextInReset ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset the input device and optionaly run diagnostics + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - Driver may perform diagnostics on reset. + + Returns: + EFI_SUCCESS - The device was reset. + EFI_DEVICE_ERROR - The device is not functioning properly and could + not be reset. + +--*/ +{ + 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; +} + +EFI_STATUS +EFIAPI +ConSplitterTextInPrivateReadKeyStroke ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + OUT EFI_INPUT_KEY *Key + ) +/*++ + + Routine Description: + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existance of a keystroke via WaitForEvent () call. + + Arguments: + This - Protocol instance pointer. + Key - Driver may perform diagnostics on reset. + + Returns: + EFI_SUCCESS - The keystroke information was returned. + EFI_NOT_READY - There was no keystroke data availiable. + EFI_DEVICE_ERROR - The keydtroke information was not returned due to + hardware errors. + +--*/ +{ + 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; +} + +BOOLEAN +ConSpliterConssoleControlStdInLocked ( + VOID + ) +/*++ + +Routine Description: + Return TRUE if StdIn is locked. The ConIn device on the virtual handle is + the only device locked. + +Arguments: + NONE + +Returns: + TRUE - StdIn locked + FALSE - StdIn working normally + +--*/ +{ + return mConIn.PasswordEnabled; +} + +VOID +EFIAPI +ConSpliterConsoleControlLockStdInEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + This timer event will fire when StdIn is locked. It will check the key + sequence on StdIn to see if it matches the password. Any error in the + password will cause the check to reset. As long a mConIn.PasswordEnabled is + TRUE the StdIn splitter will not report any input. + +Arguments: + (Standard EFI_EVENT_NOTIFY) + +Returns: + None + +--*/ +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + CHAR16 BackSpaceString[2]; + CHAR16 SpaceString[2]; + + do { + Status = ConSplitterTextInPrivateReadKeyStroke (&mConIn, &Key); + if (!EFI_ERROR (Status)) { + // + // if it's an ENTER, match password + // + if ((Key.UnicodeChar == CHAR_CARRIAGE_RETURN) && (Key.ScanCode == SCAN_NULL)) { + mConIn.PwdAttempt[mConIn.PwdIndex] = CHAR_NULL; + if (StrCmp (mConIn.Password, mConIn.PwdAttempt)) { + // + // Password not match + // + ConSplitterTextOutOutputString (&mConOut.TextOut, (CHAR16 *) L"\n\rPassword not correct\n\r"); + mConIn.PwdIndex = 0; + } else { + // + // Key matches password sequence + // + gBS->SetTimer (mConIn.LockEvent, TimerPeriodic, 0); + mConIn.PasswordEnabled = FALSE; + Status = EFI_NOT_READY; + } + } else if ((Key.UnicodeChar == CHAR_BACKSPACE) && (Key.ScanCode == SCAN_NULL)) { + // + // BackSpace met + // + if (mConIn.PwdIndex > 0) { + BackSpaceString[0] = CHAR_BACKSPACE; + BackSpaceString[1] = 0; + + SpaceString[0] = ' '; + SpaceString[1] = 0; + + ConSplitterTextOutOutputString (&mConOut.TextOut, BackSpaceString); + ConSplitterTextOutOutputString (&mConOut.TextOut, SpaceString); + ConSplitterTextOutOutputString (&mConOut.TextOut, BackSpaceString); + + mConIn.PwdIndex--; + } + } else if ((Key.ScanCode == SCAN_NULL) && (Key.UnicodeChar >= 32)) { + // + // If it's not an ENTER, neigher a function key, nor a CTRL-X or ALT-X, record the input + // + if (mConIn.PwdIndex < (MAX_STD_IN_PASSWORD - 1)) { + if (mConIn.PwdIndex == 0) { + ConSplitterTextOutOutputString (&mConOut.TextOut, (CHAR16 *) L"\n\r"); + } + + ConSplitterTextOutOutputString (&mConOut.TextOut, (CHAR16 *) L"*"); + mConIn.PwdAttempt[mConIn.PwdIndex] = Key.UnicodeChar; + mConIn.PwdIndex++; + } + } + } + } while (!EFI_ERROR (Status)); +} + +EFI_STATUS +EFIAPI +ConSpliterConsoleControlLockStdIn ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + IN CHAR16 *Password + ) +/*++ + +Routine Description: + If Password is NULL unlock the password state variable and set the event + timer. If the Password is too big return an error. If the Password is valid + Copy the Password and enable state variable and then arm the periodic timer + +Arguments: + +Returns: + EFI_SUCCESS - Lock the StdIn device + EFI_INVALID_PARAMETER - Password is NULL + EFI_OUT_OF_RESOURCES - Buffer allocation to store the password fails + +--*/ +{ + if (Password == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (StrLen (Password) >= MAX_STD_IN_PASSWORD) { + // + // Currently have a max password size + // + return EFI_OUT_OF_RESOURCES; + } + // + // Save the password, initialize state variables and arm event timer + // + StrCpy (mConIn.Password, Password); + mConIn.PasswordEnabled = TRUE; + mConIn.PwdIndex = 0; + gBS->SetTimer (mConIn.LockEvent, TimerPeriodic, (10000 * 25)); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ConSplitterTextInReadKeyStroke ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ) +/*++ + + Routine Description: + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existance of a keystroke via WaitForEvent () call. + If the ConIn is password locked make it look like no keystroke is availible + + Arguments: + This - Protocol instance pointer. + Key - Driver may perform diagnostics on reset. + + Returns: + EFI_SUCCESS - The keystroke information was returned. + EFI_NOT_READY - There was no keystroke data availiable. + EFI_DEVICE_ERROR - The keydtroke information was not returned due to + hardware errors. + +--*/ +{ + TEXT_IN_SPLITTER_PRIVATE_DATA *Private; + + Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + if (Private->PasswordEnabled) { + // + // If StdIn Locked return not ready + // + return EFI_NOT_READY; + } + + Private->KeyEventSignalState = FALSE; + + return ConSplitterTextInPrivateReadKeyStroke (Private, Key); +} + +VOID +EFIAPI +ConSplitterTextInWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + This event agregates all the events of the ConIn devices in the spliter. + If the ConIn is password locked then return. + If any events of physical ConIn devices are signaled, signal the ConIn + spliter event. This will cause the calling code to call + ConSplitterTextInReadKeyStroke (). + +Arguments: + Event - The Event assoicated with callback. + Context - Context registered when Event was created. + +Returns: + None + +--*/ +{ + EFI_STATUS Status; + TEXT_IN_SPLITTER_PRIVATE_DATA *Private; + UINTN Index; + + Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context; + if (Private->PasswordEnabled) { + // + // If StdIn Locked return not ready + // + return ; + } + + // + // if KeyEventSignalState is flagged before, and not cleared by Reset() or ReadKeyStroke() + // + if (Private->KeyEventSignalState) { + 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; + } + } +} + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerReset ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset the input device and optionaly run diagnostics + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - Driver may perform diagnostics on reset. + + Returns: + EFI_SUCCESS - The device was reset. + EFI_DEVICE_ERROR - The device is not functioning properly and could + not be reset. + +--*/ +{ + 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; +} + +STATIC +EFI_STATUS +EFIAPI +ConSplitterSimplePointerPrivateGetState ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN OUT EFI_SIMPLE_POINTER_STATE *State + ) +/*++ + + Routine Description: + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existance of a keystroke via WaitForEvent () call. + + Arguments: + This - Protocol instance pointer. + State - + + Returns: + EFI_SUCCESS - The keystroke information was returned. + EFI_NOT_READY - There was no keystroke data availiable. + EFI_DEVICE_ERROR - The keydtroke information was not returned due to + hardware errors. + +--*/ +{ + 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; +} + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerGetState ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + IN OUT EFI_SIMPLE_POINTER_STATE *State + ) +/*++ + + Routine Description: + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existance of a keystroke via WaitForEvent () call. + If the ConIn is password locked make it look like no keystroke is availible + + Arguments: + This - Protocol instance pointer. + State - + + Returns: + EFI_SUCCESS - The keystroke information was returned. + EFI_NOT_READY - There was no keystroke data availiable. + EFI_DEVICE_ERROR - The keydtroke information was not returned due to + hardware errors. + +--*/ +{ + TEXT_IN_SPLITTER_PRIVATE_DATA *Private; + + Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_SIMPLE_POINTER_THIS (This); + if (Private->PasswordEnabled) { + // + // If StdIn Locked return not ready + // + return EFI_NOT_READY; + } + + Private->InputEventSignalState = FALSE; + + return ConSplitterSimplePointerPrivateGetState (Private, State); +} + +VOID +EFIAPI +ConSplitterSimplePointerWaitForInput ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + This event agregates all the events of the ConIn devices in the spliter. + If the ConIn is password locked then return. + If any events of physical ConIn devices are signaled, signal the ConIn + spliter event. This will cause the calling code to call + ConSplitterTextInReadKeyStroke (). + +Arguments: + Event - The Event assoicated with callback. + Context - Context registered when Event was created. + +Returns: + None + +--*/ +{ + EFI_STATUS Status; + TEXT_IN_SPLITTER_PRIVATE_DATA *Private; + UINTN Index; + + Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context; + if (Private->PasswordEnabled) { + // + // If StdIn Locked return not ready + // + return ; + } + + // + // 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; + } + } +} + +EFI_STATUS +EFIAPI +ConSplitterTextOutReset ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset the text output device hardware and optionaly run diagnostics + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - Driver may perform more exhaustive verfication + operation of the device during reset. + + Returns: + EFI_SUCCESS - The text output device was reset. + EFI_DEVICE_ERROR - The text output device is not functioning correctly and + could not be reset. + +--*/ +{ + 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++) { + + if (Private->TextOutList[Index].TextOutEnabled) { + + 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_BACKGROUND_BLACK)); + + Status = DevNullTextOutSetMode (Private, 0); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + + return ReturnStatus; +} + +EFI_STATUS +EFIAPI +ConSplitterTextOutOutputString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ) +/*++ + + Routine Description: + Write a Unicode string to the output device. + + Arguments: + This - Protocol instance pointer. + String - 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. + + Returns: + EFI_SUCCESS - The string was output to the device. + EFI_DEVICE_ERROR - The device reported an error while attempting to output + the text. + EFI_UNSUPPORTED - The output device's mode is not currently in a + defined text mode. + 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 Status; + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; + UINTN Index; + UINTN BackSpaceCount; + EFI_STATUS ReturnStatus; + CHAR16 *TargetString; + + This->SetAttribute (This, This->Mode->Attribute); + + Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + + BackSpaceCount = 0; + for (TargetString = WString; *TargetString; TargetString++) { + if (*TargetString == CHAR_BACKSPACE) { + BackSpaceCount++; + } + + } + + if (BackSpaceCount == 0) { + TargetString = WString; + } else { + TargetString = AllocatePool (sizeof (CHAR16) * (StrLen (WString) + BackSpaceCount + 1)); + StrCpy (TargetString, WString); + } + // + // return the worst status met + // + Status = DevNullTextOutOutputString (Private, TargetString); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + + for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { + + if (Private->TextOutList[Index].TextOutEnabled) { + Status = Private->TextOutList[Index].TextOut->OutputString ( + Private->TextOutList[Index].TextOut, + TargetString + ); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + } + + if (BackSpaceCount) { + FreePool (TargetString); + } + + return ReturnStatus; +} + +EFI_STATUS +EFIAPI +ConSplitterTextOutTestString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ) +/*++ + + Routine Description: + Verifies that all characters in a Unicode string can be output to the + target device. + + Arguments: + This - Protocol instance pointer. + String - The NULL-terminated Unicode string to be examined for the output + device(s). + + Returns: + EFI_SUCCESS - The device(s) are capable of rendering the output string. + 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 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++) { + if (Private->TextOutList[Index].TextOutEnabled) { + 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; +} + +EFI_STATUS +EFIAPI +ConSplitterTextOutQueryMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ) +/*++ + + Routine Description: + Returns information for an available text mode that the output device(s) + supports. + + Arguments: + This - Protocol instance pointer. + ModeNumber - The mode number to return information on. + Columns, Rows - Returns the geometry of the text output device for the + requested ModeNumber. + + Returns: + EFI_SUCCESS - The requested mode information was returned. + EFI_DEVICE_ERROR - The device had an error and could not + complete the request. + EFI_UNSUPPORTED - The mode number was not valid. + +--*/ +{ + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; + + 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; + } + + *Columns = Private->TextOutQueryData[ModeNumber].Columns; + *Rows = Private->TextOutQueryData[ModeNumber].Rows; + + if (*Columns <= 0 && *Rows <= 0) { + return EFI_UNSUPPORTED; + + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ConSplitterTextOutSetMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber + ) +/*++ + + Routine Description: + Sets the output device(s) to a specified mode. + + Arguments: + This - Protocol instance pointer. + ModeNumber - The mode number to set. + + Returns: + EFI_SUCCESS - The requested text mode was set. + EFI_DEVICE_ERROR - The device had an error and + could not complete the request. + EFI_UNSUPPORTED - The mode number was not valid. + +--*/ +{ + 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++) { + + if (Private->TextOutList[Index].TextOutEnabled) { + Status = Private->TextOutList[Index].TextOut->SetMode ( + Private->TextOutList[Index].TextOut, + TextOutModeMap[Index] + ); + // + // If this console device is based on a UGA device, then sync up the bitmap from + // the UGA splitter and reclear the text portion of the display in the new mode. + // + if ((Private->TextOutList[Index].GraphicsOutput != NULL) || (Private->TextOutList[Index].UgaDraw != NULL)) { + Private->TextOutList[Index].TextOut->ClearScreen (Private->TextOutList[Index].TextOut); + } + + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + } + // + // The DevNull Console will support any possible mode as it allocates memory + // + Status = DevNullTextOutSetMode (Private, ModeNumber); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + + return ReturnStatus; +} + +EFI_STATUS +EFIAPI +ConSplitterTextOutSetAttribute ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Attribute + ) +/*++ + + Routine Description: + Sets the background and foreground colors for the OutputString () and + ClearScreen () functions. + + Arguments: + This - Protocol instance pointer. + 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. + + Returns: + EFI_SUCCESS - The attribute was set. + EFI_DEVICE_ERROR - The device had an error and + could not complete the request. + EFI_UNSUPPORTED - The attribute requested is not defined. + +--*/ +{ + 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++) { + + if (Private->TextOutList[Index].TextOutEnabled) { + Status = Private->TextOutList[Index].TextOut->SetAttribute ( + Private->TextOutList[Index].TextOut, + Attribute + ); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + } + + Private->TextOutMode.Attribute = (INT32) Attribute; + + return ReturnStatus; +} + +EFI_STATUS +EFIAPI +ConSplitterTextOutClearScreen ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + ) +/*++ + + Routine Description: + Clears the output device(s) display to the currently selected background + color. + + Arguments: + This - Protocol instance pointer. + + Returns: + EFI_SUCCESS - The operation completed successfully. + EFI_DEVICE_ERROR - The device had an error and + could not complete the request. + EFI_UNSUPPORTED - The output device is not in a valid text mode. + +--*/ +{ + 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++) { + + if (Private->TextOutList[Index].TextOutEnabled) { + Status = Private->TextOutList[Index].TextOut->ClearScreen (Private->TextOutList[Index].TextOut); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + } + + Status = DevNullTextOutClearScreen (Private); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + + return ReturnStatus; +} + +EFI_STATUS +EFIAPI +ConSplitterTextOutSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ) +/*++ + + Routine Description: + Sets the current coordinates of the cursor position + + Arguments: + This - Protocol instance pointer. + Column, Row - the position to set the cursor to. Must be greater than or + equal to zero and less than the number of columns and rows + by QueryMode (). + + Returns: + EFI_SUCCESS - The operation completed successfully. + EFI_DEVICE_ERROR - The device had an error and + could not complete the request. + EFI_UNSUPPORTED - The output device is not in a valid text mode, or the + cursor position is invalid for the current mode. + +--*/ +{ + EFI_STATUS Status; + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; + UINTN Index; + EFI_STATUS ReturnStatus; + UINTN MaxColumn; + UINTN MaxRow; + + Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + + MaxColumn = Private->TextOutQueryData[Private->TextOutMode.Mode].Columns; + MaxRow = Private->TextOutQueryData[Private->TextOutMode.Mode].Rows; + + if (Column >= MaxColumn || Row >= MaxRow) { + return EFI_UNSUPPORTED; + } + // + // return the worst status met + // + for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { + + if (Private->TextOutList[Index].TextOutEnabled) { + Status = Private->TextOutList[Index].TextOut->SetCursorPosition ( + Private->TextOutList[Index].TextOut, + Column, + Row + ); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + } + + DevNullTextOutSetCursorPosition (Private, Column, Row); + + return ReturnStatus; +} + +EFI_STATUS +EFIAPI +ConSplitterTextOutEnableCursor ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN Visible + ) +/*++ + + Routine Description: + Makes the cursor visible or invisible + + Arguments: + This - Protocol instance pointer. + Visible - If TRUE, the cursor is set to be visible. If FALSE, the cursor is + set to be invisible. + + Returns: + EFI_SUCCESS - The operation completed successfully. + EFI_DEVICE_ERROR - The device had an error and could not complete the + request, or the device does not support changing + the cursor mode. + EFI_UNSUPPORTED - The output device is not in a valid text mode. + +--*/ +{ + 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++) { + + if (Private->TextOutList[Index].TextOutEnabled) { + Status = Private->TextOutList[Index].TextOut->EnableCursor ( + Private->TextOutList[Index].TextOut, + Visible + ); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + } + + DevNullTextOutEnableCursor (Private, Visible); + + return ReturnStatus; +} diff --git a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.h b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.h new file mode 100644 index 0000000000..ac5e337689 --- /dev/null +++ b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.h @@ -0,0 +1,667 @@ +/**@file + Private data structures for the Console Splitter driver + +Copyright (c) 2006 - 2007 Intel Corporation.
+All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _CON_SPLITTER_H_ +#define _CON_SPLITTER_H_ + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +// +// Private Data Structures +// +#define CONSOLE_SPLITTER_CONSOLES_ALLOC_UNIT 32 +#define CONSOLE_SPLITTER_MODES_ALLOC_UNIT 32 +#define MAX_STD_IN_PASSWORD 80 + +typedef struct { + UINTN Columns; + UINTN Rows; +} TEXT_OUT_SPLITTER_QUERY_DATA; + +// +// Private data for the EFI_SIMPLE_TEXT_INPUT_PROTOCOL splitter +// +#define TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('T', 'i', 'S', 'p') + +typedef struct { + UINT64 Signature; + EFI_HANDLE VirtualHandle; + + EFI_SIMPLE_TEXT_INPUT_PROTOCOL TextIn; + UINTN CurrentNumberOfConsoles; + EFI_SIMPLE_TEXT_INPUT_PROTOCOL **TextInList; + UINTN TextInListCount; + + EFI_SIMPLE_POINTER_PROTOCOL SimplePointer; + EFI_SIMPLE_POINTER_MODE SimplePointerMode; + UINTN CurrentNumberOfPointers; + EFI_SIMPLE_POINTER_PROTOCOL **PointerList; + UINTN PointerListCount; + + BOOLEAN PasswordEnabled; + CHAR16 Password[MAX_STD_IN_PASSWORD]; + UINTN PwdIndex; + CHAR16 PwdAttempt[MAX_STD_IN_PASSWORD]; + EFI_EVENT LockEvent; + + BOOLEAN KeyEventSignalState; + BOOLEAN InputEventSignalState; +} TEXT_IN_SPLITTER_PRIVATE_DATA; + +#define TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS(a) \ + CR ((a), \ + TEXT_IN_SPLITTER_PRIVATE_DATA, \ + TextIn, \ + TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE \ + ) + +#define TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_SIMPLE_POINTER_THIS(a) \ + CR ((a), \ + TEXT_IN_SPLITTER_PRIVATE_DATA, \ + SimplePointer, \ + TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE \ + ) + +// +// Private data for the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL splitter +// +#define TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('T', 'o', 'S', 'p') + +typedef struct { + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; + BOOLEAN TextOutEnabled; +} TEXT_OUT_AND_GOP_DATA; + +typedef struct { + UINT32 HorizontalResolution; + UINT32 VerticalResolution; +} TEXT_OUT_GOP_MODE; + +typedef struct { + UINT64 Signature; + EFI_HANDLE VirtualHandle; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL TextOut; + EFI_SIMPLE_TEXT_OUTPUT_MODE TextOutMode; + + EFI_GRAPHICS_OUTPUT_PROTOCOL GraphicsOutput; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GraphicsOutputBlt; + TEXT_OUT_GOP_MODE *GraphicsOutputModeBuffer; + UINTN CurrentNumberOfGraphicsOutput; + BOOLEAN HardwareNeedsStarting; + + EFI_CONSOLE_CONTROL_PROTOCOL ConsoleControl; + + UINTN CurrentNumberOfConsoles; + TEXT_OUT_AND_GOP_DATA *TextOutList; + UINTN TextOutListCount; + TEXT_OUT_SPLITTER_QUERY_DATA *TextOutQueryData; + UINTN TextOutQueryDataCount; + INT32 *TextOutModeMap; + + EFI_CONSOLE_CONTROL_SCREEN_MODE ConsoleOutputMode; + + UINTN DevNullColumns; + UINTN DevNullRows; + CHAR16 *DevNullScreen; + INT32 *DevNullAttributes; + +} TEXT_OUT_SPLITTER_PRIVATE_DATA; + +#define TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS(a) \ + CR ((a), \ + TEXT_OUT_SPLITTER_PRIVATE_DATA, \ + TextOut, \ + TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE \ + ) + +#define GRAPHICS_OUTPUT_SPLITTER_PRIVATE_DATA_FROM_THIS(a) \ + CR ((a), \ + TEXT_OUT_SPLITTER_PRIVATE_DATA, \ + GraphicsOutput, \ + TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE \ + ) + +#define UGA_DRAW_SPLITTER_PRIVATE_DATA_FROM_THIS(a) \ + CR ((a), \ + TEXT_OUT_SPLITTER_PRIVATE_DATA, \ + UgaDraw, \ + TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE \ + ) + +#define CONSOLE_CONTROL_SPLITTER_PRIVATE_DATA_FROM_THIS(a) \ + CR ((a), \ + TEXT_OUT_SPLITTER_PRIVATE_DATA, \ + ConsoleControl, \ + TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE \ + ) + +// +// Function Prototypes +// +EFI_STATUS +EFIAPI +ConSplitterDriverEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + +EFI_STATUS +ConSplitterTextInConstructor ( + TEXT_IN_SPLITTER_PRIVATE_DATA *Private + ) +; + +EFI_STATUS +ConSplitterTextOutConstructor ( + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private + ) +; + +// +// Driver Binding Functions +// +EFI_STATUS +EFIAPI +ConSplitterConInDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + +EFI_STATUS +EFIAPI +ConSplitterConOutDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + +EFI_STATUS +EFIAPI +ConSplitterStdErrDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + +EFI_STATUS +EFIAPI +ConSplitterConInDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + +EFI_STATUS +EFIAPI +ConSplitterConOutDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + +EFI_STATUS +EFIAPI +ConSplitterStdErrDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + +EFI_STATUS +EFIAPI +ConSplitterConInDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +; + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +; + +EFI_STATUS +EFIAPI +ConSplitterConOutDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +; + +EFI_STATUS +EFIAPI +ConSplitterStdErrDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +; + +EFI_STATUS +EFIAPI +ConSplitterComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +ConSplitterConInComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +EFI_STATUS +EFIAPI +ConSplitterConOutComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +EFI_STATUS +EFIAPI +ConSplitterStdErrComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +// +// TextIn Constructor/Destructor functions +// +EFI_STATUS +ConSplitterTextInAddDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn + ) +; + +EFI_STATUS +ConSplitterTextInDeleteDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn + ) +; + +// +// SimplePointer Constuctor/Destructor functions +// +EFI_STATUS +ConSplitterSimplePointerAddDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer + ) +; + +EFI_STATUS +ConSplitterSimplePointerDeleteDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer + ) +; + +// +// TextOut Constuctor/Destructor functions +// +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 +ConSplitterTextOutDeleteDevice ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut + ) +; + +// +// TextIn I/O Functions +// +EFI_STATUS +EFIAPI +ConSplitterTextInReset ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextInReadKeyStroke ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ) +; + +VOID +EFIAPI +ConSplitterTextInWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ) +; + +BOOLEAN +ConSpliterConssoleControlStdInLocked ( + VOID + ) +; + +VOID +EFIAPI +ConSpliterConsoleControlLockStdInEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +; + +EFI_STATUS +EFIAPI +ConSpliterConsoleControlLockStdIn ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + IN CHAR16 *Password + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextInPrivateReadKeyStroke ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + OUT EFI_INPUT_KEY *Key + ) +; + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerReset ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +; + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerGetState ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + IN OUT EFI_SIMPLE_POINTER_STATE *State + ) +; + +VOID +EFIAPI +ConSplitterSimplePointerWaitForInput ( + IN EFI_EVENT Event, + IN VOID *Context + ) +; + +// +// TextOut I/O Functions +// +VOID +ConSplitterSynchronizeModeData ( + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextOutReset ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextOutOutputString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextOutTestString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextOutQueryMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextOutSetMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextOutSetAttribute ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Attribute + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextOutClearScreen ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextOutSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextOutEnableCursor ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN Visible + ) +; + +EFI_STATUS +ConSplitterGrowBuffer ( + IN UINTN SizeOfCount, + IN UINTN *Count, + IN OUT VOID **Buffer + ) +; + +EFI_STATUS +EFIAPI +ConSpliterConsoleControlGetMode ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode, + OUT BOOLEAN *GopExists, + OUT BOOLEAN *StdInLocked + ) +; + +EFI_STATUS +EFIAPI +ConSpliterConsoleControlSetMode ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode + ) +; + +EFI_STATUS +EFIAPI +ConSpliterGraphicsOutputQueryMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber, + OUT UINTN *SizeOfInfo, + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info + ) +; + +EFI_STATUS +EFIAPI +ConSpliterGraphicsOutputSetMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This, + IN UINT32 ModeNumber + ) +; + +EFI_STATUS +EFIAPI +ConSpliterGraphicsOutputBlt ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta OPTIONAL + ) +; + +EFI_STATUS +DevNullGopSync ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput, + IN EFI_UGA_DRAW_PROTOCOL *UgaDraw + ) +; + + +EFI_STATUS +DevNullTextOutOutputString ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN CHAR16 *WString + ) +; + +EFI_STATUS +DevNullTextOutSetMode ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN UINTN ModeNumber + ) +; + +EFI_STATUS +DevNullTextOutClearScreen ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private + ) +; + +EFI_STATUS +DevNullTextOutSetCursorPosition ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN UINTN Column, + IN UINTN Row + ) +; + +EFI_STATUS +DevNullTextOutEnableCursor ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN BOOLEAN Visible + ) +; + +EFI_STATUS +DevNullSyncGopStdOut ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private + ) +; + +#endif diff --git a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.inf b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.inf new file mode 100644 index 0000000000..a5f95e4bc1 --- /dev/null +++ b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.inf @@ -0,0 +1,120 @@ +#/** @file +# Component description file for ConSplitter module. +# +# Any Handle that attatched EFI_CONSOLE_IDENTIFIER_PROTOCOL can be bound by this driver. +# Copyright (c) 2006 - 2007, Intel Corporation +# +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ConSplitter + FILE_GUID = 408edcec-cf6d-477c-a5a8-b4844e3de281 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + EDK_RELEASE_VERSION = 0x00020000 + EFI_SPECIFICATION_VERSION = 0x00020000 + + ENTRY_POINT = InitializeConSplitter + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# +# DRIVER_BINDING = gConSplitterConInDriverBinding +# COMPONENT_NAME = gConSplitterConInComponentName +# DRIVER_BINDING = gConSplitterSimplePointerDriverBinding +# COMPONENT_NAME = gConSplitterSimplePointerComponentName +# DRIVER_BINDING = gConSplitterConOutDriverBinding +# COMPONENT_NAME = gConSplitterConOutComponentName +# DRIVER_BINDING = gConSplitterStdErrDriverBinding +# COMPONENT_NAME = gConSplitterStdErrComponentName +# + +################################################################################ +# +# Sources Section - list of files that are required for the build to succeed. +# +################################################################################ + +[Sources.common] + ConSplitterGraphics.c + ComponentName.c + ConSplitter.h + ConSplitter.c + CommonHeader.h + + +################################################################################ +# +# Package Dependency Section - list of Package files that are required for +# this module. +# +################################################################################ + +[Packages] + MdePkg/MdePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + + +################################################################################ +# +# Library Class Section - list of Library Classes that are required for +# this module. +# +################################################################################ + +[LibraryClasses] + UefiBootServicesTableLib + MemoryAllocationLib + BaseMemoryLib + BaseLib + UefiLib + UefiDriverEntryPoint + DebugLib + + +################################################################################ +# +# Guid C Name Section - list of Guids that this module uses or produces. +# +################################################################################ + +[Guids] + gEfiConsoleInDeviceGuid # ALWAYS_CONSUMED + gEfiStandardErrorDeviceGuid # ALWAYS_CONSUMED + gEfiConsoleOutDeviceGuid # ALWAYS_CONSUMED + gEfiPrimaryConsoleOutDeviceGuid # ALWAYS_PRODUCED + gEfiPrimaryConsoleInDeviceGuid # ALWAYS_PRODUCED + gEfiPrimaryStandardErrorDeviceGuid # ALWAYS_PRODUCED + + +################################################################################ +# +# Protocol C Name Section - list of Protocol and Protocol Notify C Names +# that this module uses or produces. +# +################################################################################ + +[Protocols] + gEfiConsoleControlProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiSimplePointerProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiSimpleTextInProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiSimpleTextOutProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiGraphicsOutputProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiUgaDrawProtocolGuid # PROTOCOL ALWAYS_PRODUCED + diff --git a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.msa b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.msa new file mode 100644 index 0000000000..afc35028ea --- /dev/null +++ b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.msa @@ -0,0 +1,126 @@ + + + + ConSplitter + DXE_DRIVER + 408edcec-cf6d-477c-a5a8-b4844e3de281 + 1.0 + Component description file for ConSplitter module. + Any Handle that attatched EFI_CONSOLE_IDENTIFIER_PROTOCOL can be bound by this driver. + Copyright (c) 2006 - 2007, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052 + + + IA32 X64 IPF EBC + false + ConSplitter + + + + DebugLib + Recommended libary Instance is PeiDxeDebugLibReportStatusCode instance in MdePkg. + + + UefiDriverModelLib + + + UefiDriverEntryPoint + + + UefiLib + + + BaseLib + + + BaseMemoryLib + + + MemoryAllocationLib + + + UefiBootServicesTableLib + + + + ConSplitter.c + ConSplitter.h + ComponentName.c + ConSplitterGraphics.c + + + + + + + + gEfiUgaDrawProtocolGuid + UGA Draw protocol is only installed in EFI mode. + + + gEfiGraphicsOutputProtocolGuid + Graphics Output Protocol is only installed in UEFI mode. + + + gEfiSimpleTextOutProtocolGuid + + + gEfiSimpleTextInProtocolGuid + + + gEfiSimplePointerProtocolGuid + + + gEfiConsoleControlProtocolGuid + + + + + gEfiPrimaryStandardErrorDeviceGuid + + + gEfiPrimaryConsoleInDeviceGuid + + + gEfiPrimaryConsoleOutDeviceGuid + + + gEfiConsoleOutDeviceGuid + + + gEfiStandardErrorDeviceGuid + + + gEfiConsoleInDeviceGuid + + + + EFI_SPECIFICATION_VERSION 0x00020000 + EDK_RELEASE_VERSION 0x00020000 + + ConSplitterDriverEntry + + + gConSplitterConInDriverBinding + gConSplitterConInComponentName + + + gConSplitterSimplePointerDriverBinding + gConSplitterSimplePointerComponentName + + + gConSplitterConOutDriverBinding + gConSplitterConOutComponentName + + + gConSplitterStdErrDriverBinding + gConSplitterStdErrComponentName + + + \ No newline at end of file diff --git a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterGraphics.c b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterGraphics.c new file mode 100644 index 0000000000..0387324fcf --- /dev/null +++ b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterGraphics.c @@ -0,0 +1,1222 @@ +/*++ + +Copyright (c) 2006 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ConSplitterGraphics.c + +Abstract: + + Support for ConsoleControl protocol. Support for UGA Draw spliter. + Support for DevNull Console Out. This console uses memory buffers + to represnt the console. It allows a console to start very early and + when a new console is added it is synced up with the current console + +--*/ + + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#include "ConSplitter.h" + +#include + +static CHAR16 mCrLfString[3] = { CHAR_CARRIAGE_RETURN, CHAR_LINEFEED, CHAR_NULL }; + +EFI_STATUS +EFIAPI +ConSpliterConsoleControlGetMode ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode, + OUT BOOLEAN *GopExists, + OUT BOOLEAN *StdInLocked + ) +/*++ + + Routine Description: + Return the current video mode information. Also returns info about existence + of UGA Draw devices in system, and if the Std In device is locked. All the + arguments are optional and only returned if a non NULL pointer is passed in. + + Arguments: + This - Protocol instance pointer. + Mode - Are we in text of grahics mode. + UgaExists - TRUE if UGA Spliter has found a UGA device + StdInLocked - TRUE if StdIn device is keyboard locked + + Returns: + EFI_SUCCESS - Mode information returned. + EFI_INVALID_PARAMETER - Invalid parameters. + +--*/ +{ + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; + UINTN Index; + + Private = CONSOLE_CONTROL_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + + if (Mode == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Mode = Private->ConsoleOutputMode; + + if (GopExists != NULL) { + *GopExists = FALSE; + for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) { + if ((Private->TextOutList[Index].GraphicsOutput != NULL) || (Private->TextOutList[Index].UgaDraw != NULL)) { + *GopExists = TRUE; + break; + } + } + } + + if (StdInLocked != NULL) { + *StdInLocked = ConSpliterConssoleControlStdInLocked (); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ConSpliterConsoleControlSetMode ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode + ) +/*++ + + Routine Description: + Set the current mode to either text or graphics. Graphics is + for Quiet Boot. + + Arguments: + This - Protocol instance pointer. + Mode - Mode to set the + + Returns: + EFI_SUCCESS - Mode information returned. + EFI_INVALID_PARAMETER - Invalid parameter. + EFI_UNSUPPORTED - Operation unsupported. + +--*/ +{ + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; + UINTN Index; + TEXT_OUT_AND_GOP_DATA *TextAndGop; + BOOLEAN Supported; + + Private = CONSOLE_CONTROL_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + + if (Mode >= EfiConsoleControlScreenMaxValue) { + return EFI_INVALID_PARAMETER; + } + + // + // Judge current mode with wanted mode at first. + // + if (Private->ConsoleOutputMode == Mode) { + return EFI_SUCCESS; + } + + Supported = FALSE; + TextAndGop = &Private->TextOutList[0]; + for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++, TextAndGop++) { + if ((TextAndGop->GraphicsOutput != NULL) || (TextAndGop->UgaDraw != NULL)) { + Supported = TRUE; + break; + } + } + + if ((!Supported) && (Mode == EfiConsoleControlScreenGraphics)) { + return EFI_UNSUPPORTED; + } + + Private->ConsoleOutputMode = Mode; + + TextAndGop = &Private->TextOutList[0]; + for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++, TextAndGop++) { + + TextAndGop->TextOutEnabled = TRUE; + // + // If we are going into Graphics mode disable ConOut to any UGA device + // + if ((Mode == EfiConsoleControlScreenGraphics) &&((TextAndGop->GraphicsOutput != NULL) || (TextAndGop->UgaDraw != NULL))) { + TextAndGop->TextOutEnabled = FALSE; + DevNullGopSync (Private, TextAndGop->GraphicsOutput, TextAndGop->UgaDraw); + } + } + + if (Mode == EfiConsoleControlScreenText) { + DevNullSyncGopStdOut (Private); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ConSpliterGraphicsOutputQueryMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber, + OUT UINTN *SizeOfInfo, + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info + ) +/*++ + + Routine Description: + Return the current video mode information. + + Arguments: + This - Protocol instance pointer. + ModeNumber - The mode number to return information on. + Info - Caller allocated buffer that returns information about ModeNumber. + SizeOfInfo - A pointer to the size, in bytes, of the Info buffer. + + Returns: + EFI_SUCCESS - Mode information returned. + EFI_BUFFER_TOO_SMALL - The Info buffer was too small. + EFI_DEVICE_ERROR - A hardware error occurred trying to retrieve the video mode. + EFI_NOT_STARTED - Video display is not initialized. Call SetMode () + EFI_INVALID_PARAMETER - One of the input args was NULL. + +--*/ +{ + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; + TEXT_OUT_GOP_MODE *Mode; + + if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) { + return EFI_INVALID_PARAMETER; + } + + // + // retrieve private data + // + Private = GRAPHICS_OUTPUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + + if (Private->HardwareNeedsStarting) { + return EFI_NOT_STARTED; + } + + *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); + + if (*Info == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); + + CopyMem (*Info, Private->GraphicsOutput.Mode->Info, *SizeOfInfo); + Mode = &Private->GraphicsOutputModeBuffer[ModeNumber]; + (*Info)->HorizontalResolution = Mode->HorizontalResolution; + (*Info)->VerticalResolution = Mode->VerticalResolution; + (*Info)->PixelsPerScanLine = Mode->HorizontalResolution; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ConSpliterGraphicsOutputSetMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This, + IN UINT32 ModeNumber + ) +/*++ + +Routine Description: + + Graphics output protocol interface to set video mode + + Arguments: + This - Protocol instance pointer. + ModeNumber - The mode number to be set. + + Returns: + EFI_SUCCESS - Graphics mode was changed. + EFI_DEVICE_ERROR - The device had an error and could not complete the request. + EFI_UNSUPPORTED - ModeNumber is not supported by this device. + +--*/ +{ + EFI_STATUS Status; + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; + UINTN Index; + EFI_STATUS ReturnStatus; + TEXT_OUT_GOP_MODE *Mode; + UINTN Size; + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + UINTN NumberIndex; + UINTN SizeOfInfo; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + + if (ModeNumber >= This->Mode->MaxMode) { + return EFI_UNSUPPORTED; + } + + if (ModeNumber == This->Mode->Mode) { + return EFI_SUCCESS; + } + + Private = GRAPHICS_OUTPUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + + // + // GopDevNullSetMode () + // + ReturnStatus = EFI_SUCCESS; + + // + // Free the old version + // + if (Private->GraphicsOutputBlt != NULL) { + FreePool (Private->GraphicsOutputBlt); + } + + // + // Allocate the virtual Blt buffer + // + Mode = &Private->GraphicsOutputModeBuffer[ModeNumber]; + Size = Mode->HorizontalResolution * Mode->VerticalResolution * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + Private->GraphicsOutputBlt = AllocateZeroPool (Size); + + if (Private->GraphicsOutputBlt == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (!Private->HardwareNeedsStarting) { + if (Private->ConsoleOutputMode != EfiConsoleControlScreenGraphics) { + return EFI_UNSUPPORTED; + } + } + // + // return the worst status met + // + for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) { + GraphicsOutput = Private->TextOutList[Index].GraphicsOutput; + if (GraphicsOutput != NULL) { + // + // Find corresponding ModeNumber of this GraphicsOutput instance + // + 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); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + + UgaDraw = Private->TextOutList[Index].UgaDraw; + if (UgaDraw != NULL) { + Status = UgaDraw->SetMode ( + UgaDraw, + Mode->HorizontalResolution, + Mode->VerticalResolution, + 32, + 60 + ); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + } + + This->Mode->Mode = ModeNumber; + + Info = This->Mode->Info; + Info->HorizontalResolution = Mode->HorizontalResolution; + Info->VerticalResolution = Mode->VerticalResolution; + Info->PixelsPerScanLine = Mode->HorizontalResolution; + + // + // Information is not enough here, so the following items remain unchanged: + // GraphicsOutputMode->Info->Version, GraphicsOutputMode->Info->PixelFormat + // GraphicsOutputMode->SizeOfInfo, GraphicsOutputMode->FrameBufferBase, GraphicsOutputMode->FrameBufferSize + // These items will be initialized/updated when a new GOP device is added into ConsoleSplitter. + // + + Private->HardwareNeedsStarting = FALSE; + + return ReturnStatus; +} + +STATIC +EFI_STATUS +DevNullGraphicsOutputBlt ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta OPTIONAL + ) +{ + UINTN SrcY; + BOOLEAN Forward; + UINTN Index; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltPtr; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *ScreenPtr; + UINTN HorizontalResolution; + UINTN VerticalResolution; + + if ((BltOperation < EfiBltVideoFill) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) { + return EFI_INVALID_PARAMETER; + } + + if (Width == 0 || Height == 0) { + return EFI_INVALID_PARAMETER; + } + + if (Delta == 0) { + Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + } + + HorizontalResolution = Private->GraphicsOutput.Mode->Info->HorizontalResolution; + VerticalResolution = Private->GraphicsOutput.Mode->Info->VerticalResolution; + + // + // We need to fill the Virtual Screen buffer with the blt data. + // + if (BltOperation == EfiBltVideoToBltBuffer) { + // + // Video to BltBuffer: Source is Video, destination is BltBuffer + // + if ((SourceY + Height) > VerticalResolution) { + return EFI_INVALID_PARAMETER; + } + + if ((SourceX + Width) > HorizontalResolution) { + return EFI_INVALID_PARAMETER; + } + + BltPtr = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + DestinationY * Delta + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + ScreenPtr = &Private->GraphicsOutputBlt[SourceY * HorizontalResolution + SourceX]; + while (Height) { + CopyMem (BltPtr, ScreenPtr, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + BltPtr = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltPtr + Delta); + ScreenPtr += HorizontalResolution; + Height--; + } + } else { + // + // BltBuffer to Video: Source is BltBuffer, destination is Video + // + if (DestinationY + Height > VerticalResolution) { + return EFI_INVALID_PARAMETER; + } + + if (DestinationX + Width > HorizontalResolution) { + return EFI_INVALID_PARAMETER; + } + + if ((BltOperation == EfiBltVideoToVideo) && (DestinationY > SourceY)) { + // + // Copy backwards, only care the Video to Video Blt + // + ScreenPtr = &Private->GraphicsOutputBlt[(DestinationY + Height - 1) * HorizontalResolution + DestinationX]; + SrcY = SourceY + Height - 1; + Forward = FALSE; + } else { + // + // Copy forwards, for other cases + // + ScreenPtr = &Private->GraphicsOutputBlt[DestinationY * HorizontalResolution + DestinationX]; + SrcY = SourceY; + Forward = TRUE; + } + + while (Height != 0) { + if (BltOperation == EfiBltVideoFill) { + for (Index = 0; Index < Width; Index++) { + ScreenPtr[Index] = *BltBuffer; + } + } else { + if (BltOperation == EfiBltBufferToVideo) { + BltPtr = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + SrcY * Delta + SourceX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + } else { + BltPtr = &Private->GraphicsOutputBlt[SrcY * HorizontalResolution + SourceX]; + } + + CopyMem (ScreenPtr, BltPtr, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + } + + if (Forward) { + ScreenPtr += HorizontalResolution; + SrcY ++; + } else { + ScreenPtr -= HorizontalResolution; + SrcY --; + } + Height--; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ConSpliterGraphicsOutputBlt ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta OPTIONAL + ) +/*++ + + Routine Description: + The following table defines actions for BltOperations: + EfiBltVideoFill - Write data from the BltBuffer pixel (SourceX, SourceY) + directly to every pixel of the video display rectangle + (DestinationX, DestinationY) + (DestinationX + Width, DestinationY + Height). + Only one pixel will be used from the BltBuffer. Delta is NOT used. + EfiBltVideoToBltBuffer - Read data from the video display rectangle + (SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in + the BltBuffer rectangle (DestinationX, DestinationY ) + (DestinationX + Width, DestinationY + Height). If DestinationX or + DestinationY is not zero then Delta must be set to the length in bytes + of a row in the BltBuffer. + EfiBltBufferToVideo - Write data from the BltBuffer rectangle + (SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the + video display rectangle (DestinationX, DestinationY) + (DestinationX + Width, DestinationY + Height). If SourceX or SourceY is + not zero then Delta must be set to the length in bytes of a row in the + BltBuffer. + EfiBltVideoToVideo - Copy from the video display rectangle + (SourceX, SourceY) (SourceX + Width, SourceY + Height) . + to the video display rectangle (DestinationX, DestinationY) + (DestinationX + Width, DestinationY + Height). + The BltBuffer and Delta are not used in this mode. + + Arguments: + This - Protocol instance pointer. + BltBuffer - Buffer containing data to blit into video buffer. This + buffer has a size of Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + BltOperation - Operation to perform on BlitBuffer and video memory + SourceX - X coordinate of source for the BltBuffer. + SourceY - Y coordinate of source for the BltBuffer. + DestinationX - X coordinate of destination for the BltBuffer. + DestinationY - Y coordinate of destination for the BltBuffer. + Width - Width of rectangle in BltBuffer in pixels. + Height - Hight of rectangle in BltBuffer in pixels. + Delta - + + Returns: + EFI_SUCCESS - The Blt operation completed. + EFI_INVALID_PARAMETER - BltOperation is not valid. + EFI_DEVICE_ERROR - A hardware error occured writting to the video + buffer. + +--*/ +{ + EFI_STATUS Status; + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; + UINTN Index; + EFI_STATUS ReturnStatus; + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + + Private = GRAPHICS_OUTPUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + + // + // Sync up DevNull GOP device + // + ReturnStatus = DevNullGraphicsOutputBlt ( + Private, + BltBuffer, + BltOperation, + SourceX, + SourceY, + DestinationX, + DestinationY, + Width, + Height, + Delta + ); + + if (Private->ConsoleOutputMode != EfiConsoleControlScreenGraphics) { + return ReturnStatus; + } + // + // return the worst status met + // + for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) { + GraphicsOutput = Private->TextOutList[Index].GraphicsOutput; + if (GraphicsOutput != NULL) { + Status = GraphicsOutput->Blt ( + GraphicsOutput, + BltBuffer, + BltOperation, + SourceX, + SourceY, + DestinationX, + DestinationY, + Width, + Height, + Delta + ); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } else if (BltOperation == EfiBltVideoToBltBuffer) { + // + // Only need to read the data into buffer one time + // + return EFI_SUCCESS; + } + } + + UgaDraw = Private->TextOutList[Index].UgaDraw; + if (UgaDraw != NULL) { + Status = UgaDraw->Blt ( + UgaDraw, + (EFI_UGA_PIXEL *) BltBuffer, + (EFI_UGA_BLT_OPERATION) BltOperation, + SourceX, + SourceY, + DestinationX, + DestinationY, + Width, + Height, + Delta + ); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } else if (BltOperation == EfiBltVideoToBltBuffer) { + // + // Only need to read the data into buffer one time + // + return EFI_SUCCESS; + } + } + } + + return ReturnStatus; +} + +EFI_STATUS +DevNullGopSync ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput, + IN EFI_UGA_DRAW_PROTOCOL *UgaDraw + ) +{ + if (GraphicsOutput != NULL) { + return GraphicsOutput->Blt ( + GraphicsOutput, + Private->GraphicsOutputBlt, + EfiBltBufferToVideo, + 0, + 0, + 0, + 0, + Private->GraphicsOutput.Mode->Info->HorizontalResolution, + Private->GraphicsOutput.Mode->Info->VerticalResolution, + 0 + ); + } else { + return UgaDraw->Blt ( + UgaDraw, + (EFI_UGA_PIXEL *) Private->GraphicsOutputBlt, + EfiUgaBltBufferToVideo, + 0, + 0, + 0, + 0, + Private->GraphicsOutput.Mode->Info->HorizontalResolution, + Private->GraphicsOutput.Mode->Info->VerticalResolution, + 0 + ); + } +} + + +EFI_STATUS +DevNullTextOutOutputString ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN CHAR16 *WString + ) +/*++ + + Routine Description: + Write a Unicode string to the output device. + + Arguments: + Private - Pointer to the console output splitter's private data. It + indicates the calling context. + 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. + + Returns: + EFI_SUCCESS - The string was output to the device. + EFI_DEVICE_ERROR - The device reported an error while attempting to + output the text. + EFI_UNSUPPORTED - The output device's mode is not currently in a + defined text mode. + EFI_WARN_UNKNOWN_GLYPH - This warning code indicates that some of the + characters in the Unicode string could not be + rendered and were skipped. + +--*/ +{ + UINTN SizeScreen; + UINTN SizeAttribute; + UINTN Index; + EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode; + CHAR16 *Screen; + CHAR16 *NullScreen; + CHAR16 InsertChar; + CHAR16 TempChar; + CHAR16 *PStr; + INT32 *Attribute; + INT32 *NullAttributes; + INT32 CurrentWidth; + UINTN LastRow; + UINTN MaxColumn; + + Mode = &Private->TextOutMode; + NullScreen = Private->DevNullScreen; + NullAttributes = Private->DevNullAttributes; + LastRow = Private->DevNullRows - 1; + MaxColumn = Private->DevNullColumns; + + if (Mode->Attribute & EFI_WIDE_ATTRIBUTE) { + CurrentWidth = 2; + } else { + CurrentWidth = 1; + } + + while (*WString) { + + if (*WString == CHAR_BACKSPACE) { + // + // If the cursor is at the left edge of the display, then move the cursor + // one row up. + // + if (Mode->CursorColumn == 0 && Mode->CursorRow > 0) { + Mode->CursorRow--; + Mode->CursorColumn = (INT32) MaxColumn; + } + + // + // If the cursor is not at the left edge of the display, + // then move the cursor left one column. + // + if (Mode->CursorColumn > 0) { + Mode->CursorColumn--; + if (Mode->CursorColumn > 0 && + NullAttributes[Mode->CursorRow * MaxColumn + Mode->CursorColumn - 1] & EFI_WIDE_ATTRIBUTE + ) { + Mode->CursorColumn--; + + // + // Insert an extra backspace + // + InsertChar = CHAR_BACKSPACE; + PStr = WString + 1; + while (*PStr) { + TempChar = *PStr; + *PStr = InsertChar; + InsertChar = TempChar; + PStr++; + } + + *PStr = InsertChar; + *(++PStr) = 0; + + WString++; + } + } + + WString++; + + } else if (*WString == CHAR_LINEFEED) { + // + // If the cursor is at the bottom of the display, + // then scroll the display one row, and do not update + // the cursor position. Otherwise, move the cursor down one row. + // + if (Mode->CursorRow == (INT32) (LastRow)) { + // + // Scroll Screen Up One Row + // + SizeAttribute = LastRow * MaxColumn; + CopyMem ( + NullAttributes, + NullAttributes + MaxColumn, + SizeAttribute * sizeof (INT32) + ); + + // + // Each row has an ending CHAR_NULL. So one more character each line + // for DevNullScreen than DevNullAttributes + // + SizeScreen = SizeAttribute + LastRow; + CopyMem ( + NullScreen, + NullScreen + (MaxColumn + 1), + SizeScreen * sizeof (CHAR16) + ); + + // + // Print Blank Line at last line + // + Screen = NullScreen + SizeScreen; + Attribute = NullAttributes + SizeAttribute; + + for (Index = 0; Index < MaxColumn; Index++, Screen++, Attribute++) { + *Screen = ' '; + *Attribute = Mode->Attribute; + } + } else { + Mode->CursorRow++; + } + + WString++; + } else if (*WString == CHAR_CARRIAGE_RETURN) { + // + // Move the cursor to the beginning of the current row. + // + Mode->CursorColumn = 0; + WString++; + } else { + // + // Print the character at the current cursor position and + // move the cursor right one column. If this moves the cursor + // past the right edge of the display, then the line should wrap to + // the beginning of the next line. This is equivalent to inserting + // a CR and an LF. Note that if the cursor is at the bottom of the + // display, and the line wraps, then the display will be scrolled + // one line. + // + Index = Mode->CursorRow * MaxColumn + Mode->CursorColumn; + + while (Mode->CursorColumn < (INT32) MaxColumn) { + if (*WString == CHAR_NULL) { + break; + } + + if (*WString == CHAR_BACKSPACE) { + break; + } + + if (*WString == CHAR_LINEFEED) { + break; + } + + if (*WString == CHAR_CARRIAGE_RETURN) { + break; + } + + if (*WString == WIDE_CHAR || *WString == NARROW_CHAR) { + CurrentWidth = (*WString == WIDE_CHAR) ? 2 : 1; + WString++; + continue; + } + + if (Mode->CursorColumn + CurrentWidth > (INT32) MaxColumn) { + // + // If a wide char is at the rightmost column, then move the char + // to the beginning of the next row + // + NullScreen[Index + Mode->CursorRow] = L' '; + NullAttributes[Index] = Mode->Attribute | (UINT32) EFI_WIDE_ATTRIBUTE; + Index++; + Mode->CursorColumn++; + } else { + NullScreen[Index + Mode->CursorRow] = *WString; + NullAttributes[Index] = Mode->Attribute; + if (CurrentWidth == 1) { + NullAttributes[Index] &= (~ (UINT32) EFI_WIDE_ATTRIBUTE); + } else { + NullAttributes[Index] |= (UINT32) EFI_WIDE_ATTRIBUTE; + NullAttributes[Index + 1] &= (~ (UINT32) EFI_WIDE_ATTRIBUTE); + } + + Index += CurrentWidth; + WString++; + Mode->CursorColumn += CurrentWidth; + } + } + // + // At the end of line, output carriage return and line feed + // + if (Mode->CursorColumn >= (INT32) MaxColumn) { + DevNullTextOutOutputString (Private, mCrLfString); + } + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +DevNullTextOutSetMode ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN UINTN ModeNumber + ) +/*++ + + Routine Description: + Sets the output device(s) to a specified mode. + + Arguments: + Private - Private data structure pointer. + ModeNumber - The mode number to set. + + Returns: + EFI_SUCCESS - The requested text mode was set. + EFI_DEVICE_ERROR - The device had an error and + could not complete the request. + EFI_UNSUPPORTED - The mode number was not valid. + EFI_OUT_OF_RESOURCES - Out of resources. + +--*/ +{ + UINTN Size; + UINTN Row; + UINTN Column; + TEXT_OUT_SPLITTER_QUERY_DATA *Mode; + + // + // No extra check for ModeNumber here, as it has been checked in + // ConSplitterTextOutSetMode. And mode 0 should always be supported. + // + Mode = &(Private->TextOutQueryData[ModeNumber]); + Row = Mode->Rows; + Column = Mode->Columns; + + if (Row <= 0 && Column <= 0) { + return EFI_UNSUPPORTED; + } + + if (Private->DevNullColumns != Column || Private->DevNullRows != Row) { + + Private->TextOutMode.Mode = (INT32) ModeNumber; + Private->DevNullColumns = Column; + Private->DevNullRows = Row; + + if (Private->DevNullScreen != NULL) { + FreePool (Private->DevNullScreen); + } + + Size = (Row * (Column + 1)) * sizeof (CHAR16); + Private->DevNullScreen = AllocateZeroPool (Size); + if (Private->DevNullScreen == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (Private->DevNullAttributes != NULL) { + FreePool (Private->DevNullAttributes); + } + + Size = Row * Column * sizeof (INT32); + Private->DevNullAttributes = AllocateZeroPool (Size); + if (Private->DevNullAttributes == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + DevNullTextOutClearScreen (Private); + + return EFI_SUCCESS; +} + +EFI_STATUS +DevNullTextOutClearScreen ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private + ) +/*++ + + Routine Description: + Clears the output device(s) display to the currently selected background + color. + + Arguments: + Private - Protocol instance pointer. + + Returns: + EFI_SUCCESS - The operation completed successfully. + EFI_DEVICE_ERROR - The device had an error and + could not complete the request. + EFI_UNSUPPORTED - The output device is not in a valid text mode. + +--*/ +{ + UINTN Row; + UINTN Column; + CHAR16 *Screen; + INT32 *Attributes; + INT32 CurrentAttribute; + + // + // Clear the DevNull Text Out Buffers. + // The screen is filled with spaces. + // The attributes are all synced with the current Simple Text Out Attribute + // + Screen = Private->DevNullScreen; + Attributes = Private->DevNullAttributes; + CurrentAttribute = Private->TextOutMode.Attribute; + + for (Row = 0; Row < Private->DevNullRows; Row++) { + for (Column = 0; Column < Private->DevNullColumns; Column++, Screen++, Attributes++) { + *Screen = ' '; + *Attributes = CurrentAttribute; + } + // + // Each line of the screen has a NULL on the end so we must skip over it + // + Screen++; + } + + DevNullTextOutSetCursorPosition (Private, 0, 0); + + return DevNullTextOutEnableCursor (Private, TRUE); +} + +EFI_STATUS +DevNullTextOutSetCursorPosition ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN UINTN Column, + IN UINTN Row + ) +/*++ + + Routine Description: + Sets the current coordinates of the cursor position + + Arguments: + Private - Protocol instance pointer. + Column, Row - the position to set the cursor to. Must be greater than or + equal to zero and less than the number of columns and rows + by QueryMode (). + + Returns: + EFI_SUCCESS - The operation completed successfully. + EFI_DEVICE_ERROR - The device had an error and + could not complete the request. + EFI_UNSUPPORTED - The output device is not in a valid text mode, or the + cursor position is invalid for the current mode. + +--*/ +{ + // + // 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 EFI_SUCCESS; +} + +EFI_STATUS +DevNullTextOutEnableCursor ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN BOOLEAN Visible + ) +/*++ + Routine Description: + + Implements SIMPLE_TEXT_OUTPUT.EnableCursor(). + In this driver, the cursor cannot be hidden. + + Arguments: + + Private - Indicates the calling context. + + Visible - If TRUE, the cursor is set to be visible, If FALSE, the cursor + is set to be invisible. + + Returns: + + EFI_SUCCESS - The request is valid. + + +--*/ +{ + Private->TextOutMode.CursorVisible = Visible; + + return EFI_SUCCESS; +} + +EFI_STATUS +DevNullSyncGopStdOut ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private + ) +/*++ + Routine Description: + Take the DevNull TextOut device and update the Simple Text Out on every + UGA device. + + Arguments: + Private - Indicates the calling context. + + Returns: + EFI_SUCCESS - The request is valid. + other - Return status of TextOut->OutputString () + +--*/ +{ + EFI_STATUS Status; + EFI_STATUS ReturnStatus; + UINTN Row; + UINTN Column; + UINTN List; + UINTN MaxColumn; + UINTN CurrentColumn; + UINTN StartRow; + UINTN StartColumn; + INT32 StartAttribute; + BOOLEAN StartCursorState; + CHAR16 *Screen; + CHAR16 *Str; + CHAR16 *Buffer; + CHAR16 *BufferTail; + CHAR16 *ScreenStart; + INT32 CurrentAttribute; + INT32 *Attributes; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Sto; + + // + // Save the devices Attributes, Cursor enable state and location + // + StartColumn = Private->TextOutMode.CursorColumn; + StartRow = Private->TextOutMode.CursorRow; + StartAttribute = Private->TextOutMode.Attribute; + StartCursorState = Private->TextOutMode.CursorVisible; + + for (List = 0; List < Private->CurrentNumberOfConsoles; List++) { + + Sto = Private->TextOutList[List].TextOut; + + // + // Skip non GOP/UGA devices + // + if ((Private->TextOutList[List].GraphicsOutput != NULL) || (Private->TextOutList[List].UgaDraw != NULL)) { + Sto->EnableCursor (Sto, FALSE); + Sto->ClearScreen (Sto); + } + } + + ReturnStatus = EFI_SUCCESS; + Screen = Private->DevNullScreen; + Attributes = Private->DevNullAttributes; + MaxColumn = Private->DevNullColumns; + + Buffer = AllocateZeroPool ((MaxColumn + 1) * sizeof (CHAR16)); + + for (Row = 0; Row < Private->DevNullRows; Row++, Screen += (MaxColumn + 1), Attributes += MaxColumn) { + + if (Row == (Private->DevNullRows - 1)) { + // + // Don't ever sync the last character as it will scroll the screen + // + Screen[MaxColumn - 1] = 0x00; + } + + Column = 0; + while (Column < MaxColumn) { + if (Screen[Column]) { + CurrentAttribute = Attributes[Column]; + CurrentColumn = Column; + ScreenStart = &Screen[Column]; + + // + // the line end is alway 0x0. So Column should be less than MaxColumn + // It should be still in the same row + // + for (Str = ScreenStart, BufferTail = Buffer; *Str != 0; Str++, Column++) { + + if (Attributes[Column] != CurrentAttribute) { + Column--; + break; + } + + *BufferTail = *Str; + BufferTail++; + if (Attributes[Column] & EFI_WIDE_ATTRIBUTE) { + Str++; + Column++; + } + } + + *BufferTail = 0; + + for (List = 0; List < Private->CurrentNumberOfConsoles; List++) { + + Sto = Private->TextOutList[List].TextOut; + + // + // Skip non GOP/UGA devices + // + if ((Private->TextOutList[List].GraphicsOutput != NULL) || (Private->TextOutList[List].UgaDraw != NULL)) { + Sto->SetAttribute (Sto, CurrentAttribute); + Sto->SetCursorPosition (Sto, CurrentColumn, Row); + Status = Sto->OutputString (Sto, Buffer); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + } + + } + + Column++; + } + } + // + // Restore the devices Attributes, Cursor enable state and location + // + for (List = 0; List < Private->CurrentNumberOfConsoles; List++) { + Sto = Private->TextOutList[List].TextOut; + + // + // Skip non GOP/UGA devices + // + if ((Private->TextOutList[List].GraphicsOutput != NULL) || (Private->TextOutList[List].UgaDraw != NULL)) { + Sto->SetAttribute (Sto, StartAttribute); + Sto->SetCursorPosition (Sto, StartColumn, StartRow); + Status = Sto->EnableCursor (Sto, StartCursorState); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + } + + FreePool (Buffer); + + return ReturnStatus; +} -- cgit v1.2.3