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 --- .../Universal/Console/TerminalDxe/CommonHeader.h | 51 + .../Universal/Console/TerminalDxe/ComponentName.c | 200 ++++ .../Universal/Console/TerminalDxe/EntryPoint.c | 56 + .../Universal/Console/TerminalDxe/Terminal.c | 1194 ++++++++++++++++++++ .../Universal/Console/TerminalDxe/Terminal.h | 554 +++++++++ .../Universal/Console/TerminalDxe/Terminal.inf | 117 ++ .../Universal/Console/TerminalDxe/Terminal.msa | 129 +++ .../Universal/Console/TerminalDxe/TerminalConIn.c | 1184 +++++++++++++++++++ .../Universal/Console/TerminalDxe/TerminalConOut.c | 1002 ++++++++++++++++ MdeModulePkg/Universal/Console/TerminalDxe/ansi.c | 73 ++ .../Universal/Console/TerminalDxe/vtutf8.c | 275 +++++ 11 files changed, 4835 insertions(+) create mode 100644 MdeModulePkg/Universal/Console/TerminalDxe/CommonHeader.h create mode 100644 MdeModulePkg/Universal/Console/TerminalDxe/ComponentName.c create mode 100644 MdeModulePkg/Universal/Console/TerminalDxe/EntryPoint.c create mode 100644 MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c create mode 100644 MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h create mode 100644 MdeModulePkg/Universal/Console/TerminalDxe/Terminal.inf create mode 100644 MdeModulePkg/Universal/Console/TerminalDxe/Terminal.msa create mode 100644 MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c create mode 100644 MdeModulePkg/Universal/Console/TerminalDxe/TerminalConOut.c create mode 100644 MdeModulePkg/Universal/Console/TerminalDxe/ansi.c create mode 100644 MdeModulePkg/Universal/Console/TerminalDxe/vtutf8.c (limited to 'MdeModulePkg/Universal/Console/TerminalDxe') diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/CommonHeader.h b/MdeModulePkg/Universal/Console/TerminalDxe/CommonHeader.h new file mode 100644 index 0000000000..7aca138d4e --- /dev/null +++ b/MdeModulePkg/Universal/Console/TerminalDxe/CommonHeader.h @@ -0,0 +1,51 @@ +/**@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 +// +// The Library classes this module consumes +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +// +// Driver Binding Externs +// +extern EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gTerminalComponentName; + +#endif diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/ComponentName.c b/MdeModulePkg/Universal/Console/TerminalDxe/ComponentName.c new file mode 100644 index 0000000000..9048326f5a --- /dev/null +++ b/MdeModulePkg/Universal/Console/TerminalDxe/ComponentName.c @@ -0,0 +1,200 @@ +/*++ + +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 "Terminal.h" + +// +// EFI Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gTerminalComponentName = { + TerminalComponentNameGetDriverName, + TerminalComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mTerminalDriverNameTable[] = { + { + "eng", + (CHAR16 *) L"Serial Terminal Driver" + }, + { + NULL, + NULL + } +}; + +EFI_STATUS +EFIAPI +TerminalComponentNameGetDriverName ( + 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, + gTerminalComponentName.SupportedLanguages, + mTerminalDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +TerminalComponentNameGetControllerName ( + 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 *SimpleTextOutput; + TERMINAL_DEV *TerminalDevice; + + // + // Make sure this driver is currently managing ControllHandle + // + Status = EfiTestManagedDevice ( + ControllerHandle, + gTerminalDriverBinding.DriverBindingHandle, + &gEfiSerialIoProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // This is a bus driver, so ChildHandle can not be NULL. + // + if (ChildHandle == NULL) { + return EFI_UNSUPPORTED; + } + + Status = EfiTestChildHandle ( + ControllerHandle, + ChildHandle, + &gEfiSerialIoProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get our context back + // + Status = gBS->OpenProtocol ( + ChildHandle, + &gEfiSimpleTextOutProtocolGuid, + (VOID **) &SimpleTextOutput, + gTerminalDriverBinding.DriverBindingHandle, + ChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput); + + return LookupUnicodeString ( + Language, + gTerminalComponentName.SupportedLanguages, + TerminalDevice->ControllerNameTable, + ControllerName + ); +} diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/EntryPoint.c b/MdeModulePkg/Universal/Console/TerminalDxe/EntryPoint.c new file mode 100644 index 0000000000..a8feebb1d1 --- /dev/null +++ b/MdeModulePkg/Universal/Console/TerminalDxe/EntryPoint.c @@ -0,0 +1,56 @@ +/**@file + Entry Point Source file. + + This file contains the user entry point + + 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" + +/** + The user Entry Point for module Terminal. 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 +InitializeTerminal( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Install driver model protocol(s). + // + Status = EfiLibInstallAllDriverProtocols ( + ImageHandle, + SystemTable, + &gTerminalDriverBinding, + ImageHandle, + &gTerminalComponentName, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + + return Status; +} diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c new file mode 100644 index 0000000000..01ab587bd6 --- /dev/null +++ b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c @@ -0,0 +1,1194 @@ +/*++ + +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: + + Terminal.c + +Abstract: + +Revision History: + +--*/ + + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#include "Terminal.h" + +#include "FrameworkDxe.h" + +// +// Globals +// +EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = { + TerminalDriverBindingSupported, + TerminalDriverBindingStart, + TerminalDriverBindingStop, + 0xa, + NULL, + NULL +}; + + +EFI_STATUS +EFIAPI +TerminalDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + VENDOR_DEVICE_PATH *Node; + + // + // If remaining device path is not NULL, then make sure it is a + // device path that describes a terminal communications protocol. + // + if (RemainingDevicePath != NULL) { + + Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath; + + if (Node->Header.Type != MESSAGING_DEVICE_PATH || + Node->Header.SubType != MSG_VENDOR_DP || + DevicePathNodeLength(&Node->Header) != sizeof(VENDOR_DEVICE_PATH)) { + + return EFI_UNSUPPORTED; + + } + // + // only supports PC ANSI, VT100, VT100+ and VT-UTF8 terminal types + // + if (!CompareGuid (&Node->Guid, &gEfiPcAnsiGuid) && + !CompareGuid (&Node->Guid, &gEfiVT100Guid) && + !CompareGuid (&Node->Guid, &gEfiVT100PlusGuid) && + !CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) { + + return EFI_UNSUPPORTED; + } + } + // + // Open the IO Abstraction(s) needed to perform the supported test + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + // + // The Controller must support the Serial I/O Protocol. + // This driver is a bus driver with at most 1 child device, so it is + // ok for it to be already started. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiSerialIoProtocolGuid, + (VOID **) &SerialIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Close the I/O Abstraction(s) used to perform the supported test + // + gBS->CloseProtocol ( + Controller, + &gEfiSerialIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +EFI_STATUS +EFIAPI +TerminalDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + + Start the controller. + + Arguments: + + This - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + Controller - The handle of the controller to start. + RemainingDevicePath - A pointer to the remaining portion of a devcie path. + + Returns: + + EFI_SUCCESS. + +--*/ +{ + EFI_STATUS Status; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + VENDOR_DEVICE_PATH *Node; + VENDOR_DEVICE_PATH *DefaultNode; + EFI_SERIAL_IO_MODE *Mode; + UINTN SerialInTimeOut; + TERMINAL_DEV *TerminalDevice; + UINT8 TerminalType; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; + UINTN EntryCount; + UINTN Index; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + TerminalDevice = NULL; + DefaultNode = NULL; + // + // Get the Device Path Protocol to build the device path of the child device + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { + return Status; + } + // + // Report that the remote terminal is being enabled + // + DevicePath = ParentDevicePath; + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_ENABLE, + DevicePath + ); + + // + // Open the Serial I/O Protocol BY_DRIVER. It might already be started. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiSerialIoProtocolGuid, + (VOID **) &SerialIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { + return Status; + } + + if (Status != EFI_ALREADY_STARTED) { + // + // If Serial I/O is not already open by this driver, then tag the handle + // with the Terminal Driver GUID and update the ConInDev, ConOutDev, and + // StdErrDev variables with the list of possible terminal types on this + // serial port. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiCallerIdGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + Status = gBS->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiCallerIdGuid, + DuplicateDevicePath (ParentDevicePath), + NULL + ); + if (EFI_ERROR (Status)) { + goto Error; + } + // + // if the serial device is a hot plug device, do not update the + // ConInDev, ConOutDev, and StdErrDev variables. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiHotPlugDeviceGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + TerminalUpdateConsoleDevVariable ((CHAR16 *)VarConsoleInpDev, ParentDevicePath); + TerminalUpdateConsoleDevVariable ((CHAR16 *)VarConsoleOutDev, ParentDevicePath); + TerminalUpdateConsoleDevVariable ((CHAR16 *)VarErrorOutDev, ParentDevicePath); + } + } + } + // + // Make sure a child handle does not already exist. This driver can only + // produce one child per serial port. + // + Status = gBS->OpenProtocolInformation ( + Controller, + &gEfiSerialIoProtocolGuid, + &OpenInfoBuffer, + &EntryCount + ); + if (!EFI_ERROR (Status)) { + Status = EFI_SUCCESS; + for (Index = 0; Index < EntryCount; Index++) { + if (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) { + Status = EFI_ALREADY_STARTED; + } + } + + FreePool (OpenInfoBuffer); + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // If RemainingDevicePath is NULL, then create default device path node + // + if (RemainingDevicePath == NULL) { + DefaultNode = AllocatePool (sizeof (VENDOR_DEVICE_PATH)); + if (DefaultNode == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + CopyMem (&DefaultNode->Guid, &gEfiPcAnsiGuid, sizeof (EFI_GUID)); + RemainingDevicePath = (EFI_DEVICE_PATH_PROTOCOL*) DefaultNode; + } + // + // Use the RemainingDevicePath to determine the terminal type + // + Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath; + + if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) { + + TerminalType = PcAnsiType; + + } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) { + + TerminalType = VT100Type; + + } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) { + + TerminalType = VT100PlusType; + + } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) { + + TerminalType = VTUTF8Type; + + } else { + goto Error; + } + // + // Initialize the Terminal Dev + // + TerminalDevice = AllocatePool (sizeof (TERMINAL_DEV)); + if (TerminalDevice == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + ZeroMem (TerminalDevice, sizeof (TERMINAL_DEV)); + + TerminalDevice->Signature = TERMINAL_DEV_SIGNATURE; + + TerminalDevice->TerminalType = TerminalType; + + TerminalDevice->SerialIo = SerialIo; + + // + // Simple Input Protocol + // + TerminalDevice->SimpleInput.Reset = TerminalConInReset; + TerminalDevice->SimpleInput.ReadKeyStroke = TerminalConInReadKeyStroke; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_WAIT, + TPL_NOTIFY, + TerminalConInWaitForKey, + &TerminalDevice->SimpleInput, + &TerminalDevice->SimpleInput.WaitForKey + ); + if (EFI_ERROR (Status)) { + goto Error; + } + // + // initialize the FIFO buffer used for accommodating + // the pre-read pending characters + // + InitializeRawFiFo (TerminalDevice); + InitializeUnicodeFiFo (TerminalDevice); + InitializeEfiKeyFiFo (TerminalDevice); + + // + // Set the timeout value of serial buffer for + // keystroke response performance issue + // + Mode = TerminalDevice->SerialIo->Mode; + + SerialInTimeOut = 0; + if (Mode->BaudRate != 0) { + SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate; + } + + Status = TerminalDevice->SerialIo->SetAttributes ( + TerminalDevice->SerialIo, + Mode->BaudRate, + Mode->ReceiveFifoDepth, + (UINT32) SerialInTimeOut, + (EFI_PARITY_TYPE) (Mode->Parity), + (UINT8) Mode->DataBits, + (EFI_STOP_BITS_TYPE) (Mode->StopBits) + ); + if (EFI_ERROR (Status)) { + // + // if set attributes operation fails, invalidate + // the value of SerialInTimeOut,thus make it + // inconsistent with the default timeout value + // of serial buffer. This will invoke the recalculation + // in the readkeystroke routine. + // + TerminalDevice->SerialInTimeOut = 0; + } else { + TerminalDevice->SerialInTimeOut = SerialInTimeOut; + } + // + // Build the device path for the child device + // + Status = SetTerminalDevicePath ( + TerminalDevice->TerminalType, + ParentDevicePath, + &TerminalDevice->DevicePath + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + DevicePath = TerminalDevice->DevicePath; + + Status = TerminalDevice->SimpleInput.Reset ( + &TerminalDevice->SimpleInput, + FALSE + ); + if (EFI_ERROR (Status)) { + // + // Need to report Error Code first + // + goto ReportError; + } + // + // Simple Text Output Protocol + // + TerminalDevice->SimpleTextOutput.Reset = TerminalConOutReset; + TerminalDevice->SimpleTextOutput.OutputString = TerminalConOutOutputString; + TerminalDevice->SimpleTextOutput.TestString = TerminalConOutTestString; + TerminalDevice->SimpleTextOutput.QueryMode = TerminalConOutQueryMode; + TerminalDevice->SimpleTextOutput.SetMode = TerminalConOutSetMode; + TerminalDevice->SimpleTextOutput.SetAttribute = TerminalConOutSetAttribute; + TerminalDevice->SimpleTextOutput.ClearScreen = TerminalConOutClearScreen; + TerminalDevice->SimpleTextOutput.SetCursorPosition = TerminalConOutSetCursorPosition; + TerminalDevice->SimpleTextOutput.EnableCursor = TerminalConOutEnableCursor; + TerminalDevice->SimpleTextOutput.Mode = &TerminalDevice->SimpleTextOutputMode; + + TerminalDevice->SimpleTextOutputMode.MaxMode = 1; + // + // For terminal devices, cursor is always visible + // + TerminalDevice->SimpleTextOutputMode.CursorVisible = TRUE; + TerminalDevice->SimpleTextOutputMode.Attribute = EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK); + + Status = TerminalDevice->SimpleTextOutput.Reset ( + &TerminalDevice->SimpleTextOutput, + FALSE + ); + if (EFI_ERROR (Status)) { + goto ReportError; + } + + Status = TerminalDevice->SimpleTextOutput.SetMode ( + &TerminalDevice->SimpleTextOutput, + 0 + ); + if (EFI_ERROR (Status)) { + goto ReportError; + } + + Status = TerminalDevice->SimpleTextOutput.EnableCursor ( + &TerminalDevice->SimpleTextOutput, + TRUE + ); + if (EFI_ERROR (Status)) { + goto ReportError; + } + // + // + // + TerminalDevice->InputState = INPUT_STATE_DEFAULT; + TerminalDevice->ResetState = RESET_STATE_DEFAULT; + + Status = gBS->CreateEvent ( + EVT_TIMER, + TPL_CALLBACK, + NULL, + NULL, + &TerminalDevice->TwoSecondTimeOut + ); + + // + // Build the component name for the child device + // + TerminalDevice->ControllerNameTable = NULL; + switch (TerminalDevice->TerminalType) { + case PcAnsiType: + AddUnicodeString ( + "eng", + gTerminalComponentName.SupportedLanguages, + &TerminalDevice->ControllerNameTable, + (CHAR16 *)L"PC-ANSI Serial Console" + ); + break; + + case VT100Type: + AddUnicodeString ( + "eng", + gTerminalComponentName.SupportedLanguages, + &TerminalDevice->ControllerNameTable, + (CHAR16 *)L"VT-100 Serial Console" + ); + break; + + case VT100PlusType: + AddUnicodeString ( + "eng", + gTerminalComponentName.SupportedLanguages, + &TerminalDevice->ControllerNameTable, + (CHAR16 *)L"VT-100+ Serial Console" + ); + break; + + case VTUTF8Type: + AddUnicodeString ( + "eng", + gTerminalComponentName.SupportedLanguages, + &TerminalDevice->ControllerNameTable, + (CHAR16 *)L"VT-UTF8 Serial Console" + ); + break; + } + // + // Install protocol interfaces for the serial device. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &TerminalDevice->Handle, + &gEfiDevicePathProtocolGuid, + TerminalDevice->DevicePath, + &gEfiSimpleTextInProtocolGuid, + &TerminalDevice->SimpleInput, + &gEfiSimpleTextOutProtocolGuid, + &TerminalDevice->SimpleTextOutput, + NULL + ); + if (EFI_ERROR (Status)) { + goto Error; + } + // + // if the serial device is a hot plug device, attaches the HotPlugGuid + // onto the terminal device handle. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiHotPlugDeviceGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + Status = gBS->InstallMultipleProtocolInterfaces ( + &TerminalDevice->Handle, + &gEfiHotPlugDeviceGuid, + NULL, + NULL + ); + } + // + // Register the Parent-Child relationship via + // EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiSerialIoProtocolGuid, + (VOID **) &TerminalDevice->SerialIo, + This->DriverBindingHandle, + TerminalDevice->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + if (DefaultNode != NULL) { + FreePool (DefaultNode); + } + + return EFI_SUCCESS; + +ReportError: + // + // Report error code before exiting + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR, + DevicePath + ); + +Error: + // + // Use the Stop() function to free all resources allocated in Start() + // + if (TerminalDevice != NULL) { + + if (TerminalDevice->Handle != NULL) { + This->Stop (This, Controller, 1, &TerminalDevice->Handle); + } else { + + if (TerminalDevice->TwoSecondTimeOut != NULL) { + gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut); + } + + if (TerminalDevice->SimpleInput.WaitForKey != NULL) { + gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey); + } + + if (TerminalDevice->ControllerNameTable != NULL) { + FreeUnicodeStringTable (TerminalDevice->ControllerNameTable); + } + + if (TerminalDevice->DevicePath != NULL) { + FreePool (TerminalDevice->DevicePath); + } + + FreePool (TerminalDevice); + } + } + + if (DefaultNode != NULL) { + FreePool (DefaultNode); + } + + This->Stop (This, Controller, 0, NULL); + + return Status; +} + +EFI_STATUS +EFIAPI +TerminalDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + + Stop a device controller. + + Arguments: + + This - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + Controller - A handle to the device being stopped. + NumberOfChildren - The number of child device handles in ChildHandleBuffer. + ChildHandleBuffer - An array of child handles to be freed. + + Returns: + + EFI_SUCCESS - Operation successful. + EFI_DEVICE_ERROR - Devices error. + +--*/ +{ + EFI_STATUS Status; + UINTN Index; + BOOLEAN AllChildrenStopped; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput; + TERMINAL_DEV *TerminalDevice; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + Status = gBS->HandleProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &DevicePath + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Report that the remote terminal is being disabled + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_DISABLE, + DevicePath + ); + + // + // Complete all outstanding transactions to Controller. + // Don't allow any new transaction to Controller to be started. + // + if (NumberOfChildren == 0) { + // + // Close the bus driver + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiCallerIdGuid, + (VOID **) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + // + // Remove Parent Device Path from + // the Console Device Environment Variables + // + TerminalRemoveConsoleDevVariable ((CHAR16 *)VarConsoleInpDev, ParentDevicePath); + TerminalRemoveConsoleDevVariable ((CHAR16 *)VarConsoleOutDev, ParentDevicePath); + TerminalRemoveConsoleDevVariable ((CHAR16 *)VarErrorOutDev, ParentDevicePath); + + // + // Uninstall the Terminal Driver's GUID Tag from the Serial controller + // + Status = gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiCallerIdGuid, + ParentDevicePath, + NULL + ); + + // + // Free the ParentDevicePath that was duplicated in Start() + // + if (!EFI_ERROR (Status)) { + FreePool (ParentDevicePath); + } + } + + gBS->CloseProtocol ( + Controller, + &gEfiSerialIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return EFI_SUCCESS; + } + + AllChildrenStopped = TRUE; + + for (Index = 0; Index < NumberOfChildren; Index++) { + + Status = gBS->OpenProtocol ( + ChildHandleBuffer[Index], + &gEfiSimpleTextOutProtocolGuid, + (VOID **) &SimpleTextOutput, + This->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + + TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput); + + gBS->CloseProtocol ( + Controller, + &gEfiSerialIoProtocolGuid, + This->DriverBindingHandle, + ChildHandleBuffer[Index] + ); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + ChildHandleBuffer[Index], + &gEfiSimpleTextInProtocolGuid, + &TerminalDevice->SimpleInput, + &gEfiSimpleTextOutProtocolGuid, + &TerminalDevice->SimpleTextOutput, + &gEfiDevicePathProtocolGuid, + TerminalDevice->DevicePath, + NULL + ); + if (EFI_ERROR (Status)) { + gBS->OpenProtocol ( + Controller, + &gEfiSerialIoProtocolGuid, + (VOID **) &SerialIo, + This->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + } else { + + if (TerminalDevice->ControllerNameTable != NULL) { + FreeUnicodeStringTable (TerminalDevice->ControllerNameTable); + } + + Status = gBS->OpenProtocol ( + ChildHandleBuffer[Index], + &gEfiHotPlugDeviceGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + Status = gBS->UninstallMultipleProtocolInterfaces ( + ChildHandleBuffer[Index], + &gEfiHotPlugDeviceGuid, + NULL, + NULL + ); + } else { + Status = EFI_SUCCESS; + } + + gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut); + gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey); + FreePool (TerminalDevice->DevicePath); + FreePool (TerminalDevice); + } + } + + if (EFI_ERROR (Status)) { + AllChildrenStopped = FALSE; + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +VOID +TerminalUpdateConsoleDevVariable ( + IN CHAR16 *VariableName, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath + ) +{ + EFI_STATUS Status; + UINTN VariableSize; + UINT8 TerminalType; + EFI_DEVICE_PATH_PROTOCOL *Variable; + EFI_DEVICE_PATH_PROTOCOL *NewVariable; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + + Variable = NULL; + + // + // Get global variable and its size according to the name given. + // + Variable = TerminalGetVariableAndSize ( + VariableName, + &gEfiGlobalVariableGuid, + &VariableSize + ); + // + // Append terminal device path onto the variable. + // + for (TerminalType = PcAnsiType; TerminalType <= VTUTF8Type; TerminalType++) { + SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath); + NewVariable = AppendDevicePathInstance (Variable, TempDevicePath); + if (Variable != NULL) { + FreePool (Variable); + } + + if (TempDevicePath != NULL) { + FreePool (TempDevicePath); + } + + Variable = NewVariable; + } + + VariableSize = GetDevicePathSize (Variable); + + Status = gRT->SetVariable ( + VariableName, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + VariableSize, + Variable + ); + ASSERT_EFI_ERROR (Status); + FreePool (Variable); + + return ; +} + +VOID +TerminalRemoveConsoleDevVariable ( + IN CHAR16 *VariableName, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath + ) +/*++ + + Routine Description: + + Remove console device variable. + + Arguments: + + VariableName - A pointer to the variable name. + ParentDevicePath - A pointer to the parent device path. + + Returns: + +--*/ +{ + EFI_STATUS Status; + BOOLEAN FoundOne; + BOOLEAN Match; + UINTN VariableSize; + UINTN InstanceSize; + UINT8 TerminalType; + EFI_DEVICE_PATH_PROTOCOL *Instance; + EFI_DEVICE_PATH_PROTOCOL *Variable; + EFI_DEVICE_PATH_PROTOCOL *OriginalVariable; + EFI_DEVICE_PATH_PROTOCOL *NewVariable; + EFI_DEVICE_PATH_PROTOCOL *SavedNewVariable; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + + Variable = NULL; + Instance = NULL; + + // + // Get global variable and its size according to the name given. + // + Variable = TerminalGetVariableAndSize ( + VariableName, + &gEfiGlobalVariableGuid, + &VariableSize + ); + if (Variable == NULL) { + return ; + } + + FoundOne = FALSE; + OriginalVariable = Variable; + NewVariable = NULL; + + // + // Get first device path instance from Variable + // + Instance = GetNextDevicePathInstance (&Variable, &InstanceSize); + if (Instance == NULL) { + FreePool (OriginalVariable); + return ; + } + // + // Loop through all the device path instances of Variable + // + do { + // + // Loop through all the terminal types that this driver supports + // + Match = FALSE; + for (TerminalType = PcAnsiType; TerminalType <= VTUTF8Type; TerminalType++) { + + SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath); + + // + // Compare the genterated device path to the current device path instance + // + if (TempDevicePath != NULL) { + if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) { + Match = TRUE; + FoundOne = TRUE; + } + + FreePool (TempDevicePath); + } + } + // + // If a match was not found, then keep the current device path instance + // + if (!Match) { + SavedNewVariable = NewVariable; + NewVariable = AppendDevicePathInstance (NewVariable, Instance); + if (SavedNewVariable != NULL) { + FreePool (SavedNewVariable); + } + } + // + // Get next device path instance from Variable + // + FreePool (Instance); + Instance = GetNextDevicePathInstance (&Variable, &InstanceSize); + } while (Instance != NULL); + + FreePool (OriginalVariable); + + if (FoundOne) { + VariableSize = GetDevicePathSize (NewVariable); + + Status = gRT->SetVariable ( + VariableName, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + VariableSize, + NewVariable + ); + ASSERT_EFI_ERROR (Status); + } + + if (NewVariable != NULL) { + FreePool (NewVariable); + } + + return ; +} + +VOID * +TerminalGetVariableAndSize ( + IN CHAR16 *Name, + IN EFI_GUID *VendorGuid, + OUT UINTN *VariableSize + ) +/*++ + +Routine Description: + Read the EFI variable (VendorGuid/Name) and return a dynamically allocated + buffer, and the size of the buffer. On failure return NULL. + +Arguments: + Name - String part of EFI variable name + + VendorGuid - GUID part of EFI variable name + + VariableSize - Returns the size of the EFI variable that was read + +Returns: + Dynamically allocated memory that contains a copy of the EFI variable. + Caller is repsoncible freeing the buffer. + + NULL - Variable was not read + +--*/ +{ + EFI_STATUS Status; + UINTN BufferSize; + VOID *Buffer; + + Buffer = NULL; + + // + // Pass in a small size buffer to find the actual variable size. + // + BufferSize = 1; + Buffer = AllocatePool (BufferSize); + if (Buffer == NULL) { + *VariableSize = 0; + return NULL; + } + + Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer); + + if (Status == EFI_SUCCESS) { + *VariableSize = BufferSize; + return Buffer; + + } else if (Status == EFI_BUFFER_TOO_SMALL) { + // + // Allocate the buffer to return + // + FreePool (Buffer); + Buffer = AllocatePool (BufferSize); + if (Buffer == NULL) { + *VariableSize = 0; + return NULL; + } + // + // Read variable into the allocated buffer. + // + Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer); + if (EFI_ERROR (Status)) { + BufferSize = 0; + FreePool (Buffer); + Buffer = NULL; + } + } else { + // + // Variable not found or other errors met. + // + BufferSize = 0; + FreePool (Buffer); + Buffer = NULL; + } + + *VariableSize = BufferSize; + return Buffer; +} + +EFI_STATUS +SetTerminalDevicePath ( + IN UINT8 TerminalType, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, + OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath + ) +{ + VENDOR_DEVICE_PATH Node; + + *TerminalDevicePath = NULL; + Node.Header.Type = MESSAGING_DEVICE_PATH; + Node.Header.SubType = MSG_VENDOR_DP; + + // + // generate terminal device path node according to terminal type. + // + switch (TerminalType) { + + case PcAnsiType: + CopyMem ( + &Node.Guid, + &gEfiPcAnsiGuid, + sizeof (EFI_GUID) + ); + break; + + case VT100Type: + CopyMem ( + &Node.Guid, + &gEfiVT100Guid, + sizeof (EFI_GUID) + ); + break; + + case VT100PlusType: + CopyMem ( + &Node.Guid, + &gEfiVT100PlusGuid, + sizeof (EFI_GUID) + ); + break; + + case VTUTF8Type: + CopyMem ( + &Node.Guid, + &gEfiVTUTF8Guid, + sizeof (EFI_GUID) + ); + break; + + default: + return EFI_UNSUPPORTED; + break; + } + + SetDevicePathNodeLength ( + &Node.Header, + sizeof (VENDOR_DEVICE_PATH) + ); + // + // append the terminal node onto parent device path + // to generate a complete terminal device path. + // + *TerminalDevicePath = AppendDevicePathNode ( + ParentDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &Node + ); + if (*TerminalDevicePath == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +VOID +InitializeRawFiFo ( + IN TERMINAL_DEV *TerminalDevice + ) +{ + // + // Make the raw fifo empty. + // + TerminalDevice->RawFiFo.Head = TerminalDevice->RawFiFo.Tail; +} + +VOID +InitializeUnicodeFiFo ( + IN TERMINAL_DEV *TerminalDevice + ) +{ + // + // Make the unicode fifo empty + // + TerminalDevice->UnicodeFiFo.Head = TerminalDevice->UnicodeFiFo.Tail; +} + +VOID +InitializeEfiKeyFiFo ( + IN TERMINAL_DEV *TerminalDevice + ) +{ + // + // Make the efi key fifo empty + // + TerminalDevice->EfiKeyFiFo.Head = TerminalDevice->EfiKeyFiFo.Tail; +} diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h new file mode 100644 index 0000000000..7ec24b3091 --- /dev/null +++ b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h @@ -0,0 +1,554 @@ +/*++ + +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: + + terminal.h + +Abstract: + + +Revision History + +--*/ + +#ifndef _TERMINAL_H +#define _TERMINAL_H + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#define RAW_FIFO_MAX_NUMBER 256 +#define FIFO_MAX_NUMBER 128 + +typedef struct { + UINT8 Head; + UINT8 Tail; + UINT8 Data[RAW_FIFO_MAX_NUMBER + 1]; +} RAW_DATA_FIFO; + +typedef struct { + UINT8 Head; + UINT8 Tail; + UINT16 Data[FIFO_MAX_NUMBER + 1]; +} UNICODE_FIFO; + +typedef struct { + UINT8 Head; + UINT8 Tail; + EFI_INPUT_KEY Data[FIFO_MAX_NUMBER + 1]; +} EFI_KEY_FIFO; + +#define TERMINAL_DEV_SIGNATURE EFI_SIGNATURE_32 ('t', 'm', 'n', 'l') + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + UINT8 TerminalType; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + VENDOR_DEVICE_PATH Node; + EFI_SIMPLE_TEXT_INPUT_PROTOCOL SimpleInput; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL SimpleTextOutput; + EFI_SIMPLE_TEXT_OUTPUT_MODE SimpleTextOutputMode; + UINTN SerialInTimeOut; + RAW_DATA_FIFO RawFiFo; + UNICODE_FIFO UnicodeFiFo; + EFI_KEY_FIFO EfiKeyFiFo; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + EFI_EVENT TwoSecondTimeOut; + UINT32 InputState; + UINT32 ResetState; + + // + // Esc could not be output to the screen by user, + // but the terminal driver need to output it to + // the terminal emulation software to send control sequence. + // This boolean is used by the terminal driver only + // to indicate whether the Esc could be sent or not. + // + BOOLEAN OutputEscChar; +} TERMINAL_DEV; + +#define INPUT_STATE_DEFAULT 0x00 +#define INPUT_STATE_ESC 0x01 +#define INPUT_STATE_CSI 0x02 +#define INPUT_STATE_LEFTOPENBRACKET 0x04 +#define INPUT_STATE_O 0x08 +#define INPUT_STATE_2 0x10 + +#define RESET_STATE_DEFAULT 0x00 +#define RESET_STATE_ESC_R 0x01 +#define RESET_STATE_ESC_R_ESC_r 0x02 + +#define TERMINAL_CON_IN_DEV_FROM_THIS(a) CR (a, TERMINAL_DEV, SimpleInput, TERMINAL_DEV_SIGNATURE) +#define TERMINAL_CON_OUT_DEV_FROM_THIS(a) CR (a, TERMINAL_DEV, SimpleTextOutput, TERMINAL_DEV_SIGNATURE) + +typedef union { + UINT8 Utf8_1; + UINT8 Utf8_2[2]; + UINT8 Utf8_3[3]; +} UTF8_CHAR; + +#define PcAnsiType 0 +#define VT100Type 1 +#define VT100PlusType 2 +#define VTUTF8Type 3 + +#define LEFTOPENBRACKET 0x5b // '[' +#define ACAP 0x41 +#define BCAP 0x42 +#define CCAP 0x43 +#define DCAP 0x44 + +#define MODE0_COLUMN_COUNT 80 +#define MODE0_ROW_COUNT 25 + +#define BACKSPACE 8 +#define ESC 27 +#define CSI 0x9B +#define DEL 127 +#define BRIGHT_CONTROL_OFFSET 2 +#define FOREGROUND_CONTROL_OFFSET 6 +#define BACKGROUND_CONTROL_OFFSET 11 +#define ROW_OFFSET 2 +#define COLUMN_OFFSET 5 + +typedef struct { + UINT16 Unicode; + CHAR8 PcAnsi; + CHAR8 Ascii; +} UNICODE_TO_CHAR; + +#define VarConsoleInpDev L"ConInDev" +#define VarConsoleOutDev L"ConOutDev" +#define VarErrorOutDev L"ErrOutDev" + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gTerminalComponentName; + +// +// Prototypes +// +EFI_STATUS +EFIAPI +InitializeTerminal ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + +EFI_STATUS +EFIAPI +TerminalConInReset ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +; + +EFI_STATUS +EFIAPI +TerminalConInReadKeyStroke ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ) +; + +VOID +EFIAPI +TerminalConInWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ) +; + +EFI_STATUS +EFIAPI +TerminalConOutReset ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +; + +EFI_STATUS +EFIAPI +TerminalConOutOutputString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ) +; + +EFI_STATUS +EFIAPI +TerminalConOutTestString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ) +; + +EFI_STATUS +EFIAPI +TerminalConOutQueryMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ) +; + +EFI_STATUS +EFIAPI +TerminalConOutSetMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber + ) +; + +EFI_STATUS +EFIAPI +TerminalConOutSetAttribute ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Attribute + ) +; + +EFI_STATUS +EFIAPI +TerminalConOutClearScreen ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + ) +; + +EFI_STATUS +EFIAPI +TerminalConOutSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ) +; + +EFI_STATUS +EFIAPI +TerminalConOutEnableCursor ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN Visible + ) +; + +EFI_STATUS +EFIAPI +TerminalDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +TerminalDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +TerminalDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +EFI_STATUS +EFIAPI +TerminalComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +TerminalComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +// +// internal functions +// +EFI_STATUS +TerminalConInCheckForKey ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This + ) +; + +VOID +TerminalUpdateConsoleDevVariable ( + IN CHAR16 *VariableName, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath + ) +; + +VOID +TerminalRemoveConsoleDevVariable ( + IN CHAR16 *VariableName, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath + ) +; + +VOID * +TerminalGetVariableAndSize ( + IN CHAR16 *Name, + IN EFI_GUID *VendorGuid, + OUT UINTN *VariableSize + ) +; + +EFI_STATUS +SetTerminalDevicePath ( + IN UINT8 TerminalType, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, + OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath + ) +; + +VOID +InitializeRawFiFo ( + IN TERMINAL_DEV *TerminalDevice + ) +; + +VOID +InitializeUnicodeFiFo ( + IN TERMINAL_DEV *TerminalDevice + ) +; + +VOID +InitializeEfiKeyFiFo ( + IN TERMINAL_DEV *TerminalDevice + ) +; + +EFI_STATUS +GetOneKeyFromSerial ( + EFI_SERIAL_IO_PROTOCOL *SerialIo, + UINT8 *Input + ) +; + +BOOLEAN +RawFiFoInsertOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT8 Input + ) +; + +BOOLEAN +RawFiFoRemoveOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT8 *Output + ) +; + +BOOLEAN +IsRawFiFoEmpty ( + TERMINAL_DEV *TerminalDevice + ) +; + +BOOLEAN +IsRawFiFoFull ( + TERMINAL_DEV *TerminalDevice + ) +; + +BOOLEAN +EfiKeyFiFoInsertOneKey ( + TERMINAL_DEV *TerminalDevice, + EFI_INPUT_KEY Key + ) +; + +BOOLEAN +EfiKeyFiFoRemoveOneKey ( + TERMINAL_DEV *TerminalDevice, + EFI_INPUT_KEY *Output + ) +; + +BOOLEAN +IsEfiKeyFiFoEmpty ( + TERMINAL_DEV *TerminalDevice + ) +; + +BOOLEAN +IsEfiKeyFiFoFull ( + TERMINAL_DEV *TerminalDevice + ) +; + +BOOLEAN +UnicodeFiFoInsertOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT16 Input + ) +; + +BOOLEAN +UnicodeFiFoRemoveOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT16 *Output + ) +; + +BOOLEAN +IsUnicodeFiFoEmpty ( + TERMINAL_DEV *TerminalDevice + ) +; + +BOOLEAN +IsUnicodeFiFoFull ( + TERMINAL_DEV *TerminalDevice + ) +; + +UINT8 +UnicodeFiFoGetKeyCount ( + TERMINAL_DEV *TerminalDevice + ) +; + +VOID +TranslateRawDataToEfiKey ( + IN TERMINAL_DEV *TerminalDevice + ) +; + +// +// internal functions for PC ANSI +// +VOID +AnsiRawDataToUnicode ( + IN TERMINAL_DEV *PcAnsiDevice + ) +; + +VOID +UnicodeToEfiKey ( + IN TERMINAL_DEV *PcAnsiDevice + ) +; + +EFI_STATUS +AnsiTestString ( + IN TERMINAL_DEV *TerminalDevice, + IN CHAR16 *WString + ) +; + +// +// internal functions for VT100 +// +EFI_STATUS +VT100TestString ( + IN TERMINAL_DEV *VT100Device, + IN CHAR16 *WString + ) +; + +// +// internal functions for VT100Plus +// +EFI_STATUS +VT100PlusTestString ( + IN TERMINAL_DEV *TerminalDevice, + IN CHAR16 *WString + ) +; + +// +// internal functions for VTUTF8 +// +VOID +VTUTF8RawDataToUnicode ( + IN TERMINAL_DEV *VtUtf8Device + ) +; + +EFI_STATUS +VTUTF8TestString ( + IN TERMINAL_DEV *TerminalDevice, + IN CHAR16 *WString + ) +; + +VOID +UnicodeToUtf8 ( + IN CHAR16 Unicode, + OUT UTF8_CHAR *Utf8Char, + OUT UINT8 *ValidBytes + ) +; + +VOID +GetOneValidUtf8Char ( + IN TERMINAL_DEV *Utf8Device, + OUT UTF8_CHAR *Utf8Char, + OUT UINT8 *ValidBytes + ) +; + +VOID +Utf8ToUnicode ( + IN UTF8_CHAR Utf8Char, + IN UINT8 ValidBytes, + OUT CHAR16 *UnicodeChar + ) +; + +// +// functions for boxdraw unicode +// +BOOLEAN +TerminalIsValidTextGraphics ( + IN CHAR16 Graphic, + OUT CHAR8 *PcAnsi, OPTIONAL + OUT CHAR8 *Ascii OPTIONAL + ) +; + +BOOLEAN +TerminalIsValidAscii ( + IN CHAR16 Ascii + ) +; + +BOOLEAN +TerminalIsValidEfiCntlChar ( + IN CHAR16 CharC + ) +; + +#endif diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.inf b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.inf new file mode 100644 index 0000000000..358db95606 --- /dev/null +++ b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.inf @@ -0,0 +1,117 @@ +#/** @file +# Component description file for Terminal module. +# +# This driver installs Simple Text In/Out protocol for terminal devices (serial devices or hotplug devices). +# 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 = Terminal + FILE_GUID = 9E863906-A40F-4875-977F-5B93FF237FC6 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + EDK_RELEASE_VERSION = 0x00020000 + EFI_SPECIFICATION_VERSION = 0x00020000 + + ENTRY_POINT = InitializeTerminal + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# +# DRIVER_BINDING = gTerminalDriverBinding +# COMPONENT_NAME = gTerminalComponentName +# + +################################################################################ +# +# Sources Section - list of files that are required for the build to succeed. +# +################################################################################ + +[Sources.common] + ComponentName.c + vtutf8.c + ansi.c + TerminalConOut.c + TerminalConIn.c + Terminal.c + Terminal.h + CommonHeader.h + EntryPoint.c + + +################################################################################ +# +# 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] + DevicePathLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + MemoryAllocationLib + BaseMemoryLib + ReportStatusCodeLib + UefiLib + UefiDriverEntryPoint + DebugLib + + +################################################################################ +# +# Guid C Name Section - list of Guids that this module uses or produces. +# +################################################################################ + +[Guids] + gEfiGlobalVariableGuid # SOMETIMES_CONSUMED L"ErrOutDev" + gEfiVTUTF8Guid # SOMETIMES_CONSUMED + gEfiVT100Guid # SOMETIMES_CONSUMED + gEfiVT100PlusGuid # SOMETIMES_CONSUMED + gEfiPcAnsiGuid # SOMETIMES_CONSUMED + + +################################################################################ +# +# Protocol C Name Section - list of Protocol and Protocol Notify C Names +# that this module uses or produces. +# +################################################################################ + +[Protocols] + gEfiHotPlugDeviceGuid # PROTOCOL SOMETIMES_CONSUMED + gEfiSerialIoProtocolGuid # PROTOCOL TO_START + gEfiDevicePathProtocolGuid # PROTOCOL TO_START + gEfiSimpleTextInProtocolGuid # PROTOCOL BY_START + gEfiSimpleTextOutProtocolGuid # PROTOCOL BY_START + diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.msa b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.msa new file mode 100644 index 0000000000..1c1dc0680d --- /dev/null +++ b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.msa @@ -0,0 +1,129 @@ + + + + Terminal + DXE_DRIVER + 9E863906-A40F-4875-977F-5B93FF237FC6 + 1.0 + Component description file for Terminal module. + This driver installs Simple Text In/Out protocol for terminal devices (serial devices or hotplug devices). + 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 + Terminal + + + + DebugLib + Recommended libary Instance is PeiDxeDebugLibReportStatusCode instance in MdePkg. + + + UefiDriverModelLib + + + UefiDriverEntryPoint + + + UefiLib + + + ReportStatusCodeLib + + + BaseMemoryLib + + + MemoryAllocationLib + + + UefiBootServicesTableLib + + + UefiRuntimeServicesTableLib + + + DevicePathLib + + + + Terminal.h + Terminal.c + TerminalConIn.c + TerminalConOut.c + ansi.c + vtutf8.c + ComponentName.c + + + + + + + + gEfiSimpleTextOutProtocolGuid + + + gEfiSimpleTextInProtocolGuid + + + gEfiDevicePathProtocolGuid + + + gEfiSerialIoProtocolGuid + + + gEfiHotPlugDeviceGuid + + + + + 0x0043 0x006F 0x006E 0x0049 0x006E 0x0044 0x0065 0x0076 + gEfiGlobalVariableGuid + L"ConInDev" global variable will be updated if the serial device is not a hot plug device. + + + 0x0043 0x006F 0x006E 0x004F 0x0075 0x0074 0x0044 0x0065 0x0076 + gEfiGlobalVariableGuid + L"ConOutDev" global variable will be updated if the serial device is not a hot plug device. + + + 0x0045 0x0072 0x0072 0x004F 0x0075 0x0074 0x0044 0x0065 0x0076 + gEfiGlobalVariableGuid + L"ErrOutDev" global variable will be updated if the serial device is not a hot plug device. + + + + + gEfiGlobalVariableGuid + + + gEfiPcAnsiGuid + + + gEfiVT100PlusGuid + + + gEfiVT100Guid + + + gEfiVTUTF8Guid + + + + EFI_SPECIFICATION_VERSION 0x00020000 + EDK_RELEASE_VERSION 0x00020000 + + gTerminalDriverBinding + gTerminalComponentName + + + \ No newline at end of file diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c new file mode 100644 index 0000000000..952024b712 --- /dev/null +++ b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c @@ -0,0 +1,1184 @@ +/**@file + Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol. + +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 "Terminal.h" + +#include "FrameworkDxe.h" + +EFI_STATUS +EFIAPI +TerminalConInReset ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset(). + This driver only perform dependent serial device reset regardless of + the value of ExtendeVerification + + Arguments: + + This - Indicates the calling context. + + ExtendedVerification - Skip by this driver. + + Returns: + + EFI_SUCCESS + The reset operation succeeds. + + EFI_DEVICE_ERROR + The dependent serial port reset fails. + +--*/ +{ + EFI_STATUS Status; + TERMINAL_DEV *TerminalDevice; + + TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This); + + // + // Report progress code here + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_RESET, + TerminalDevice->DevicePath + ); + + Status = TerminalDevice->SerialIo->Reset (TerminalDevice->SerialIo); + + // + // clear all the internal buffer for keys + // + InitializeRawFiFo (TerminalDevice); + InitializeUnicodeFiFo (TerminalDevice); + InitializeEfiKeyFiFo (TerminalDevice); + + if (EFI_ERROR (Status)) { + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR, + TerminalDevice->DevicePath + ); + } + + return Status; +} + +EFI_STATUS +EFIAPI +TerminalConInReadKeyStroke ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke(). + + Arguments: + + This - Indicates the calling context. + + Key - A pointer to a buffer that is filled in with the keystroke + information for the key that was sent from terminal. + + Returns: + + EFI_SUCCESS + The keystroke information is returned successfully. + + EFI_NOT_READY + There is no keystroke data available. + + EFI_DEVICE_ERROR + The dependent serial device encounters error. + +--*/ +{ + TERMINAL_DEV *TerminalDevice; + EFI_STATUS Status; + + // + // Initialize *Key to nonsense value. + // + Key->ScanCode = SCAN_NULL; + Key->UnicodeChar = 0; + // + // get TERMINAL_DEV from "This" parameter. + // + TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This); + + Status = TerminalConInCheckForKey (This); + if (EFI_ERROR (Status)) { + return EFI_NOT_READY; + } + + EfiKeyFiFoRemoveOneKey (TerminalDevice, Key); + + return EFI_SUCCESS; + +} + +VOID +TranslateRawDataToEfiKey ( + IN TERMINAL_DEV *TerminalDevice + ) +/*++ + Step1: Turn raw data into Unicode (according to different encode). + Step2: Translate Unicode into key information. + (according to different terminal standard). +--*/ +{ + switch (TerminalDevice->TerminalType) { + + case PcAnsiType: + case VT100Type: + case VT100PlusType: + AnsiRawDataToUnicode (TerminalDevice); + UnicodeToEfiKey (TerminalDevice); + break; + + case VTUTF8Type: + // + // Process all the raw data in the RawFIFO, + // put the processed key into UnicodeFIFO. + // + VTUTF8RawDataToUnicode (TerminalDevice); + + // + // Translate all the Unicode data in the UnicodeFIFO to Efi key, + // then put into EfiKeyFIFO. + // + UnicodeToEfiKey (TerminalDevice); + + break; + } +} + +VOID +EFIAPI +TerminalConInWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + Routine Description: + + Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event + Signal the event if there is key available + + Arguments: + + Event - Indicates the event that invoke this function. + + Context - Indicates the calling context. + + Returns: + + N/A + +--*/ +{ + // + // Someone is waiting on the keystroke event, if there's + // a key pending, signal the event + // + // Context is the pointer to EFI_SIMPLE_TEXT_INPUT_PROTOCOL + // + if (!EFI_ERROR (TerminalConInCheckForKey (Context))) { + + gBS->SignalEvent (Event); + } +} + +EFI_STATUS +TerminalConInCheckForKey ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This + ) +/*++ + Routine Description: + + Check for a pending key in the Efi Key FIFO or Serial device buffer. + + Arguments: + + This - Indicates the calling context. + + Returns: + + EFI_SUCCESS + There is key pending. + + EFI_NOT_READY + There is no key pending. + + EFI_DEVICE_ERROR + +--*/ +{ + EFI_STATUS Status; + TERMINAL_DEV *TerminalDevice; + UINT32 Control; + UINT8 Input; + EFI_SERIAL_IO_MODE *Mode; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + UINTN SerialInTimeOut; + + TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This); + + SerialIo = TerminalDevice->SerialIo; + if (SerialIo == NULL) { + return EFI_DEVICE_ERROR; + } + // + // if current timeout value for serial device is not identical with + // the value saved in TERMINAL_DEV structure, then recalculate the + // timeout value again and set serial attribute according to this value. + // + Mode = SerialIo->Mode; + if (Mode->Timeout != TerminalDevice->SerialInTimeOut) { + + SerialInTimeOut = 0; + if (Mode->BaudRate != 0) { + SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate; + } + + Status = SerialIo->SetAttributes ( + SerialIo, + Mode->BaudRate, + Mode->ReceiveFifoDepth, + (UINT32) SerialInTimeOut, + (EFI_PARITY_TYPE) (Mode->Parity), + (UINT8) Mode->DataBits, + (EFI_STOP_BITS_TYPE) (Mode->StopBits) + ); + + if (EFI_ERROR (Status)) { + TerminalDevice->SerialInTimeOut = 0; + } else { + TerminalDevice->SerialInTimeOut = SerialInTimeOut; + } + } + // + // check whether serial buffer is empty + // + Status = SerialIo->GetControl (SerialIo, &Control); + + if (Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) { + // + // Translate all the raw data in RawFIFO into EFI Key, + // according to different terminal type supported. + // + TranslateRawDataToEfiKey (TerminalDevice); + + // + // if there is pre-fetched Efi Key in EfiKeyFIFO buffer, + // return directly. + // + if (!IsEfiKeyFiFoEmpty (TerminalDevice)) { + return EFI_SUCCESS; + } else { + return EFI_NOT_READY; + } + } + // + // Fetch all the keys in the serial buffer, + // and insert the byte stream into RawFIFO. + // + do { + + Status = GetOneKeyFromSerial (TerminalDevice->SerialIo, &Input); + + if (EFI_ERROR (Status)) { + if (Status == EFI_DEVICE_ERROR) { + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_INPUT_ERROR, + TerminalDevice->DevicePath + ); + } + break; + } + + RawFiFoInsertOneKey (TerminalDevice, Input); + } while (TRUE); + + // + // Translate all the raw data in RawFIFO into EFI Key, + // according to different terminal type supported. + // + TranslateRawDataToEfiKey (TerminalDevice); + + if (IsEfiKeyFiFoEmpty (TerminalDevice)) { + return EFI_NOT_READY; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +GetOneKeyFromSerial ( + EFI_SERIAL_IO_PROTOCOL *SerialIo, + UINT8 *Input + ) +/*++ + Get one key out of serial buffer. + If serial buffer is empty, return EFI_NOT_READY; + if reading serial buffer encounter error, returns EFI_DEVICE_ERROR; + if reading serial buffer successfully, put the fetched key to + the parameter "Input", and return EFI_SUCCESS. +--*/ +{ + EFI_STATUS Status; + UINTN Size; + + Size = 1; + *Input = 0; + + Status = SerialIo->Read (SerialIo, &Size, Input); + + if (EFI_ERROR (Status)) { + + if (Status == EFI_TIMEOUT) { + return EFI_NOT_READY; + } + + return EFI_DEVICE_ERROR; + + } + + if (*Input == 0) { + return EFI_NOT_READY; + } + + return EFI_SUCCESS; +} + +BOOLEAN +RawFiFoInsertOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT8 Input + ) +/*++ + Insert one byte raw data into the Raw Data FIFO. + If FIFO is FULL before data insertion, + return FALSE, and the key is lost. +--*/ +{ + UINT8 Tail; + + Tail = TerminalDevice->RawFiFo.Tail; + + if (IsRawFiFoFull (TerminalDevice)) { + // + // Raw FIFO is full + // + return FALSE; + } + + TerminalDevice->RawFiFo.Data[Tail] = Input; + + TerminalDevice->RawFiFo.Tail = (UINT8) ((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1)); + + return TRUE; +} + +BOOLEAN +RawFiFoRemoveOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT8 *Output + ) +/*++ + Remove one byte raw data out of the Raw Data FIFO. + If FIFO buffer is empty before remove operation, + return FALSE. +--*/ +{ + UINT8 Head; + + Head = TerminalDevice->RawFiFo.Head; + + if (IsRawFiFoEmpty (TerminalDevice)) { + // + // FIFO is empty + // + *Output = 0; + return FALSE; + } + + *Output = TerminalDevice->RawFiFo.Data[Head]; + + TerminalDevice->RawFiFo.Head = (UINT8) ((Head + 1) % (RAW_FIFO_MAX_NUMBER + 1)); + + return TRUE; +} + +BOOLEAN +IsRawFiFoEmpty ( + TERMINAL_DEV *TerminalDevice + ) +/*++ + Clarify whether FIFO buffer is empty. +--*/ +{ + if (TerminalDevice->RawFiFo.Head == TerminalDevice->RawFiFo.Tail) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsRawFiFoFull ( + TERMINAL_DEV *TerminalDevice + ) +/*++ + Clarify whether FIFO buffer is full. +--*/ +{ + UINT8 Tail; + UINT8 Head; + + Tail = TerminalDevice->RawFiFo.Tail; + Head = TerminalDevice->RawFiFo.Head; + + if (((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1)) == Head) { + + return TRUE; + } + + return FALSE; +} + +BOOLEAN +EfiKeyFiFoInsertOneKey ( + TERMINAL_DEV *TerminalDevice, + EFI_INPUT_KEY Key + ) +/*++ + Insert one pre-fetched key into the FIFO buffer. + If FIFO buffer is FULL before key insertion, + return FALSE, and the key is lost. +--*/ +{ + UINT8 Tail; + + Tail = TerminalDevice->EfiKeyFiFo.Tail; + + if (IsEfiKeyFiFoFull (TerminalDevice)) { + // + // Efi Key FIFO is full + // + return FALSE; + } + + TerminalDevice->EfiKeyFiFo.Data[Tail] = Key; + + TerminalDevice->EfiKeyFiFo.Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1)); + + return TRUE; +} + +BOOLEAN +EfiKeyFiFoRemoveOneKey ( + TERMINAL_DEV *TerminalDevice, + EFI_INPUT_KEY *Output + ) +/*++ + Remove one pre-fetched key out of the FIFO buffer. + If FIFO buffer is empty before remove operation, + return FALSE. +--*/ +{ + UINT8 Head; + + Head = TerminalDevice->EfiKeyFiFo.Head; + + if (IsEfiKeyFiFoEmpty (TerminalDevice)) { + // + // FIFO is empty + // + Output->ScanCode = SCAN_NULL; + Output->UnicodeChar = 0; + return FALSE; + } + + *Output = TerminalDevice->EfiKeyFiFo.Data[Head]; + + TerminalDevice->EfiKeyFiFo.Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1)); + + return TRUE; +} + +BOOLEAN +IsEfiKeyFiFoEmpty ( + TERMINAL_DEV *TerminalDevice + ) +/*++ + Clarify whether FIFO buffer is empty. +--*/ +{ + if (TerminalDevice->EfiKeyFiFo.Head == TerminalDevice->EfiKeyFiFo.Tail) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsEfiKeyFiFoFull ( + TERMINAL_DEV *TerminalDevice + ) +/*++ + Clarify whether FIFO buffer is full. +--*/ +{ + UINT8 Tail; + UINT8 Head; + + Tail = TerminalDevice->EfiKeyFiFo.Tail; + Head = TerminalDevice->EfiKeyFiFo.Head; + + if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) { + + return TRUE; + } + + return FALSE; +} + +BOOLEAN +UnicodeFiFoInsertOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT16 Input + ) +/*++ + Insert one pre-fetched key into the FIFO buffer. + If FIFO buffer is FULL before key insertion, + return FALSE, and the key is lost. +--*/ +{ + UINT8 Tail; + + Tail = TerminalDevice->UnicodeFiFo.Tail; + + if (IsUnicodeFiFoFull (TerminalDevice)) { + // + // Unicode FIFO is full + // + return FALSE; + } + + TerminalDevice->UnicodeFiFo.Data[Tail] = Input; + + TerminalDevice->UnicodeFiFo.Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1)); + + return TRUE; +} + +BOOLEAN +UnicodeFiFoRemoveOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT16 *Output + ) +/*++ + Remove one pre-fetched key out of the FIFO buffer. + If FIFO buffer is empty before remove operation, + return FALSE. +--*/ +{ + UINT8 Head; + + Head = TerminalDevice->UnicodeFiFo.Head; + + if (IsUnicodeFiFoEmpty (TerminalDevice)) { + // + // FIFO is empty + // + Output = NULL; + return FALSE; + } + + *Output = TerminalDevice->UnicodeFiFo.Data[Head]; + + TerminalDevice->UnicodeFiFo.Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1)); + + return TRUE; +} + +BOOLEAN +IsUnicodeFiFoEmpty ( + TERMINAL_DEV *TerminalDevice + ) +/*++ + Clarify whether FIFO buffer is empty. +--*/ +{ + if (TerminalDevice->UnicodeFiFo.Head == TerminalDevice->UnicodeFiFo.Tail) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsUnicodeFiFoFull ( + TERMINAL_DEV *TerminalDevice + ) +/*++ + Clarify whether FIFO buffer is full. +--*/ +{ + UINT8 Tail; + UINT8 Head; + + Tail = TerminalDevice->UnicodeFiFo.Tail; + Head = TerminalDevice->UnicodeFiFo.Head; + + if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) { + + return TRUE; + } + + return FALSE; +} + +UINT8 +UnicodeFiFoGetKeyCount ( + TERMINAL_DEV *TerminalDevice + ) +{ + UINT8 Tail; + UINT8 Head; + + Tail = TerminalDevice->UnicodeFiFo.Tail; + Head = TerminalDevice->UnicodeFiFo.Head; + + if (Tail >= Head) { + return (UINT8) (Tail - Head); + } else { + return (UINT8) (Tail + FIFO_MAX_NUMBER + 1 - Head); + } +} + +STATIC +VOID +UnicodeToEfiKeyFlushState ( + IN TERMINAL_DEV *TerminalDevice + ) +{ + EFI_INPUT_KEY Key; + + if (TerminalDevice->InputState & INPUT_STATE_ESC) { + Key.ScanCode = SCAN_ESC; + Key.UnicodeChar = 0; + EfiKeyFiFoInsertOneKey (TerminalDevice, Key); + } + + if (TerminalDevice->InputState & INPUT_STATE_CSI) { + Key.ScanCode = SCAN_NULL; + Key.UnicodeChar = CSI; + EfiKeyFiFoInsertOneKey (TerminalDevice, Key); + } + + if (TerminalDevice->InputState & INPUT_STATE_LEFTOPENBRACKET) { + Key.ScanCode = SCAN_NULL; + Key.UnicodeChar = LEFTOPENBRACKET; + EfiKeyFiFoInsertOneKey (TerminalDevice, Key); + } + + if (TerminalDevice->InputState & INPUT_STATE_O) { + Key.ScanCode = SCAN_NULL; + Key.UnicodeChar = 'O'; + EfiKeyFiFoInsertOneKey (TerminalDevice, Key); + } + + if (TerminalDevice->InputState & INPUT_STATE_2) { + Key.ScanCode = SCAN_NULL; + Key.UnicodeChar = '2'; + EfiKeyFiFoInsertOneKey (TerminalDevice, Key); + } + + gBS->SetTimer ( + TerminalDevice->TwoSecondTimeOut, + TimerCancel, + 0 + ); + + TerminalDevice->InputState = INPUT_STATE_DEFAULT; +} + +VOID +UnicodeToEfiKey ( + IN TERMINAL_DEV *TerminalDevice + ) +/*++ + Routine Description: + + Converts a stream of Unicode characters from a terminal input device into EFI Keys that + can be read through the Simple Input Protocol. The table below shows the keyboard + input mappings that this function supports. If the ESC sequence listed in one of the + columns is presented, then it is translated into the coorespoding EFI Scan Code. If a + matching sequence is not found, then the raw key strokes are converted into EFI Keys. + + 2 seconds are allowed for an ESC sequence to be completed. If the ESC sequence is not + completed in 2 seconds, then the raw key strokes of the partial ESC sequence are + converted into EFI Keys. + + There is one special input sequence that will force the system to reset. + This is ESC R ESC r ESC R. + + Arguments: + + TerminaDevice : The terminal device to use to translate raw input into EFI Keys + + Returns: + + None + +Symbols used in table below +=========================== + ESC = 0x1B + CSI = 0x9B + DEL = 0x7f + ^ = CTRL + ++=========+======+===========+==========+==========+ +| | EFI | EFI 1.10 | | | +| | Scan | | VT100+ | | +| KEY | Code | PC ANSI | VTUTF8 | VT100 | ++=========+======+===========+==========+==========+ +| NULL | 0x00 | | | | +| UP | 0x01 | ESC [ A | ESC [ A | ESC [ A | +| DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B | +| RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C | +| LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D | +| HOME | 0x05 | ESC [ H | ESC h | ESC [ H | +| END | 0x06 | ESC [ F | ESC k | ESC [ K | +| INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ | +| | | ESC [ L | | ESC [ L | +| DELETE | 0x08 | ESC [ X | ESC - | ESC [ P | +| PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V | +| | | | | ESC [ ? | +| PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U | +| | | | | ESC [ / | +| F1 | 0x0B | ESC [ M | ESC 1 | ESC O P | +| F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q | +| F3 | 0x0D | ESC [ O | ESC 3 | ESC O w | +| F4 | 0x0E | ESC [ P | ESC 4 | ESC O x | +| F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t | +| F6 | 0x10 | ESC [ R | ESC 6 | ESC O u | +| F7 | 0x11 | ESC [ S | ESC 7 | ESC O q | +| F8 | 0x12 | ESC [ T | ESC 8 | ESC O r | +| F9 | 0x13 | ESC [ U | ESC 9 | ESC O p | +| F10 | 0x14 | ESC [ V | ESC 0 | ESC O M | +| Escape | 0x17 | ESC | ESC | ESC | ++=========+======+===========+==========+=========+ + +Special Mappings +================ +ESC R ESC r ESC R = Reset System + +--*/ +{ + EFI_STATUS Status; + EFI_STATUS TimerStatus; + UINT16 UnicodeChar; + EFI_INPUT_KEY Key; + BOOLEAN SetDefaultResetState; + + TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut); + + if (!EFI_ERROR (TimerStatus)) { + UnicodeToEfiKeyFlushState (TerminalDevice); + TerminalDevice->ResetState = RESET_STATE_DEFAULT; + } + + while (!IsUnicodeFiFoEmpty(TerminalDevice)) { + + if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) { + // + // Check to see if the 2 second timer has expired + // + TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut); + if (!EFI_ERROR (TimerStatus)) { + UnicodeToEfiKeyFlushState (TerminalDevice); + TerminalDevice->ResetState = RESET_STATE_DEFAULT; + } + } + + // + // Fetch one Unicode character from the Unicode FIFO + // + UnicodeFiFoRemoveOneKey (TerminalDevice,&UnicodeChar); + + SetDefaultResetState = TRUE; + + switch (TerminalDevice->InputState) { + case INPUT_STATE_DEFAULT: + + break; + + case INPUT_STATE_ESC: + + if (UnicodeChar == LEFTOPENBRACKET) { + TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET; + TerminalDevice->ResetState = RESET_STATE_DEFAULT; + continue; + } + + if (UnicodeChar == 'O' && TerminalDevice->TerminalType == VT100Type) { + TerminalDevice->InputState |= INPUT_STATE_O; + TerminalDevice->ResetState = RESET_STATE_DEFAULT; + continue; + } + + Key.ScanCode = SCAN_NULL; + + if (TerminalDevice->TerminalType == VT100PlusType || + TerminalDevice->TerminalType == VTUTF8Type) { + switch (UnicodeChar) { + case '1': + Key.ScanCode = SCAN_F1; + break; + case '2': + Key.ScanCode = SCAN_F2; + break; + case '3': + Key.ScanCode = SCAN_F3; + break; + case '4': + Key.ScanCode = SCAN_F4; + break; + case '5': + Key.ScanCode = SCAN_F5; + break; + case '6': + Key.ScanCode = SCAN_F6; + break; + case '7': + Key.ScanCode = SCAN_F7; + break; + case '8': + Key.ScanCode = SCAN_F8; + break; + case '9': + Key.ScanCode = SCAN_F9; + break; + case '0': + Key.ScanCode = SCAN_F10; + break; + case 'h': + Key.ScanCode = SCAN_HOME; + break; + case 'k': + Key.ScanCode = SCAN_END; + break; + case '+': + Key.ScanCode = SCAN_INSERT; + break; + case '-': + Key.ScanCode = SCAN_DELETE; + break; + case '/': + Key.ScanCode = SCAN_PAGE_DOWN; + break; + case '?': + Key.ScanCode = SCAN_PAGE_UP; + break; + default : + break; + } + } + + switch (UnicodeChar) { + case 'R': + if (TerminalDevice->ResetState == RESET_STATE_DEFAULT) { + TerminalDevice->ResetState = RESET_STATE_ESC_R; + SetDefaultResetState = FALSE; + } else if (TerminalDevice->ResetState == RESET_STATE_ESC_R_ESC_r) { + gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL); + } + Key.ScanCode = SCAN_NULL; + break; + case 'r': + if (TerminalDevice->ResetState == RESET_STATE_ESC_R) { + TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_r; + SetDefaultResetState = FALSE; + } + Key.ScanCode = SCAN_NULL; + break; + default : + break; + } + + if (SetDefaultResetState) { + TerminalDevice->ResetState = RESET_STATE_DEFAULT; + } + + if (Key.ScanCode != SCAN_NULL) { + Key.UnicodeChar = 0; + EfiKeyFiFoInsertOneKey (TerminalDevice,Key); + TerminalDevice->InputState = INPUT_STATE_DEFAULT; + UnicodeToEfiKeyFlushState (TerminalDevice); + continue; + } + + UnicodeToEfiKeyFlushState (TerminalDevice); + + break; + + case INPUT_STATE_ESC | INPUT_STATE_O: + + TerminalDevice->ResetState = RESET_STATE_DEFAULT; + + Key.ScanCode = SCAN_NULL; + + if (TerminalDevice->TerminalType == VT100Type) { + switch (UnicodeChar) { + case 'P': + Key.ScanCode = SCAN_F1; + break; + case 'Q': + Key.ScanCode = SCAN_F2; + break; + case 'w': + Key.ScanCode = SCAN_F3; + break; + case 'x': + Key.ScanCode = SCAN_F4; + break; + case 't': + Key.ScanCode = SCAN_F5; + break; + case 'u': + Key.ScanCode = SCAN_F6; + break; + case 'q': + Key.ScanCode = SCAN_F7; + break; + case 'r': + Key.ScanCode = SCAN_F8; + break; + case 'p': + Key.ScanCode = SCAN_F9; + break; + case 'M': + Key.ScanCode = SCAN_F10; + break; + default : + break; + } + } + + if (Key.ScanCode != SCAN_NULL) { + Key.UnicodeChar = 0; + EfiKeyFiFoInsertOneKey (TerminalDevice,Key); + TerminalDevice->InputState = INPUT_STATE_DEFAULT; + UnicodeToEfiKeyFlushState (TerminalDevice); + continue; + } + + UnicodeToEfiKeyFlushState (TerminalDevice); + + break; + + case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET: + + TerminalDevice->ResetState = RESET_STATE_DEFAULT; + + Key.ScanCode = SCAN_NULL; + + if (TerminalDevice->TerminalType == PcAnsiType || + TerminalDevice->TerminalType == VT100Type || + TerminalDevice->TerminalType == VT100PlusType || + TerminalDevice->TerminalType == VTUTF8Type) { + switch (UnicodeChar) { + case 'A': + Key.ScanCode = SCAN_UP; + break; + case 'B': + Key.ScanCode = SCAN_DOWN; + break; + case 'C': + Key.ScanCode = SCAN_RIGHT; + break; + case 'D': + Key.ScanCode = SCAN_LEFT; + break; + case 'H': + if (TerminalDevice->TerminalType == PcAnsiType || + TerminalDevice->TerminalType == VT100Type) { + Key.ScanCode = SCAN_HOME; + } + break; + case 'F': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_END; + } + break; + case 'K': + if (TerminalDevice->TerminalType == VT100Type) { + Key.ScanCode = SCAN_END; + } + break; + case 'L': + case '@': + if (TerminalDevice->TerminalType == PcAnsiType || + TerminalDevice->TerminalType == VT100Type) { + Key.ScanCode = SCAN_INSERT; + } + break; + case 'X': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_DELETE; + } + break; + case 'P': + if (TerminalDevice->TerminalType == VT100Type) { + Key.ScanCode = SCAN_DELETE; + } else if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F4; + } + break; + case 'I': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_PAGE_UP; + } + break; + case 'V': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F10; + } + case '?': + if (TerminalDevice->TerminalType == VT100Type) { + Key.ScanCode = SCAN_PAGE_UP; + } + break; + case 'G': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_PAGE_DOWN; + } + break; + case 'U': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F9; + } + case '/': + if (TerminalDevice->TerminalType == VT100Type) { + Key.ScanCode = SCAN_PAGE_DOWN; + } + break; + case 'M': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F1; + } + break; + case 'N': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F2; + } + break; + case 'O': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F3; + } + break; + case 'Q': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F5; + } + break; + case 'R': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F6; + } + break; + case 'S': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F7; + } + break; + case 'T': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F8; + } + break; + default : + break; + } + } + + if (Key.ScanCode != SCAN_NULL) { + Key.UnicodeChar = 0; + EfiKeyFiFoInsertOneKey (TerminalDevice,Key); + TerminalDevice->InputState = INPUT_STATE_DEFAULT; + UnicodeToEfiKeyFlushState (TerminalDevice); + continue; + } + + UnicodeToEfiKeyFlushState (TerminalDevice); + + break; + + + default: + // + // Invalid state. This should never happen. + // + ASSERT (FALSE); + + UnicodeToEfiKeyFlushState (TerminalDevice); + + break; + } + + if (UnicodeChar == ESC) { + TerminalDevice->InputState = INPUT_STATE_ESC; + } + + if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) { + Status = gBS->SetTimer( + TerminalDevice->TwoSecondTimeOut, + TimerRelative, + (UINT64)20000000 + ); + ASSERT_EFI_ERROR (Status); + continue; + } + + if (SetDefaultResetState) { + TerminalDevice->ResetState = RESET_STATE_DEFAULT; + } + + if (UnicodeChar == DEL) { + Key.ScanCode = SCAN_DELETE; + Key.UnicodeChar = 0; + } else { + Key.ScanCode = SCAN_NULL; + Key.UnicodeChar = UnicodeChar; + } + + EfiKeyFiFoInsertOneKey (TerminalDevice,Key); + } +} diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConOut.c b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConOut.c new file mode 100644 index 0000000000..b5a9f33e14 --- /dev/null +++ b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConOut.c @@ -0,0 +1,1002 @@ +/*++ + +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: + + TerminalConOut.c + +Abstract: + + +Revision History +--*/ + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#include "Terminal.h" + +#include "FrameworkDxe.h" + +// +// This list is used to define the valid extend chars. +// It also provides a mapping from Unicode to PCANSI or +// ASCII. The ASCII mapping we just made up. +// +// +STATIC UNICODE_TO_CHAR UnicodeToPcAnsiOrAscii[] = { + { BOXDRAW_HORIZONTAL, 0xc4, L'-' }, + { BOXDRAW_VERTICAL, 0xb3, L'|' }, + { BOXDRAW_DOWN_RIGHT, 0xda, L'/' }, + { BOXDRAW_DOWN_LEFT, 0xbf, L'\\' }, + { BOXDRAW_UP_RIGHT, 0xc0, L'\\' }, + { BOXDRAW_UP_LEFT, 0xd9, L'/' }, + { BOXDRAW_VERTICAL_RIGHT, 0xc3, L'|' }, + { BOXDRAW_VERTICAL_LEFT, 0xb4, L'|' }, + { BOXDRAW_DOWN_HORIZONTAL, 0xc2, L'+' }, + { BOXDRAW_UP_HORIZONTAL, 0xc1, L'+' }, + { BOXDRAW_VERTICAL_HORIZONTAL, 0xc5, L'+' }, + { BOXDRAW_DOUBLE_HORIZONTAL, 0xcd, L'-' }, + { BOXDRAW_DOUBLE_VERTICAL, 0xba, L'|' }, + { BOXDRAW_DOWN_RIGHT_DOUBLE, 0xd5, L'/' }, + { BOXDRAW_DOWN_DOUBLE_RIGHT, 0xd6, L'/' }, + { BOXDRAW_DOUBLE_DOWN_RIGHT, 0xc9, L'/' }, + { BOXDRAW_DOWN_LEFT_DOUBLE, 0xb8, L'\\' }, + { BOXDRAW_DOWN_DOUBLE_LEFT, 0xb7, L'\\' }, + { BOXDRAW_DOUBLE_DOWN_LEFT, 0xbb, L'\\' }, + { BOXDRAW_UP_RIGHT_DOUBLE, 0xd4, L'\\' }, + { BOXDRAW_UP_DOUBLE_RIGHT, 0xd3, L'\\' }, + { BOXDRAW_DOUBLE_UP_RIGHT, 0xc8, L'\\' }, + { BOXDRAW_UP_LEFT_DOUBLE, 0xbe, L'/' }, + { BOXDRAW_UP_DOUBLE_LEFT, 0xbd, L'/' }, + { BOXDRAW_DOUBLE_UP_LEFT, 0xbc, L'/' }, + { BOXDRAW_VERTICAL_RIGHT_DOUBLE, 0xc6, L'|' }, + { BOXDRAW_VERTICAL_DOUBLE_RIGHT, 0xc7, L'|' }, + { BOXDRAW_DOUBLE_VERTICAL_RIGHT, 0xcc, L'|' }, + { BOXDRAW_VERTICAL_LEFT_DOUBLE, 0xb5, L'|' }, + { BOXDRAW_VERTICAL_DOUBLE_LEFT, 0xb6, L'|' }, + { BOXDRAW_DOUBLE_VERTICAL_LEFT, 0xb9, L'|' }, + { BOXDRAW_DOWN_HORIZONTAL_DOUBLE, 0xd1, L'+' }, + { BOXDRAW_DOWN_DOUBLE_HORIZONTAL, 0xd2, L'+' }, + { BOXDRAW_DOUBLE_DOWN_HORIZONTAL, 0xcb, L'+' }, + { BOXDRAW_UP_HORIZONTAL_DOUBLE, 0xcf, L'+' }, + { BOXDRAW_UP_DOUBLE_HORIZONTAL, 0xd0, L'+' }, + { BOXDRAW_DOUBLE_UP_HORIZONTAL, 0xca, L'+' }, + { BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE, 0xd8, L'+' }, + { BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL, 0xd7, L'+' }, + { BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL, 0xce, L'+' }, + + { BLOCKELEMENT_FULL_BLOCK, 0xdb, L'*' }, + { BLOCKELEMENT_LIGHT_SHADE, 0xb0, L'+' }, + + { GEOMETRICSHAPE_UP_TRIANGLE, 0x1e, L'^' }, + { GEOMETRICSHAPE_RIGHT_TRIANGLE, 0x10, L'>' }, + { GEOMETRICSHAPE_DOWN_TRIANGLE, 0x1f, L'v' }, + { GEOMETRICSHAPE_LEFT_TRIANGLE, 0x11, L'<' }, + + { ARROW_LEFT, 0x3c, L'<' }, + { ARROW_UP, 0x18, L'^' }, + { ARROW_RIGHT, 0x3e, L'>' }, + { ARROW_DOWN, 0x19, L'v' }, + + { 0x0000, 0x00, L'\0' } +}; + +CHAR16 mSetModeString[] = { ESC, '[', '=', '3', 'h', 0 }; +CHAR16 mSetAttributeString[] = { ESC, '[', '0', 'm', ESC, '[', '4', '0', 'm', ESC, '[', '4', '0', 'm', 0 }; +CHAR16 mClearScreenString[] = { ESC, '[', '2', 'J', 0 }; +CHAR16 mSetCursorPositionString[] = { ESC, '[', '0', '0', ';', '0', '0', 'H', 0 }; + +// +// Body of the ConOut functions +// +EFI_STATUS +EFIAPI +TerminalConOutReset ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.Reset(). + If ExtendeVerification is TRUE, then perform dependent serial device reset, + and set display mode to mode 0. + If ExtendedVerification is FALSE, only set display mode to mode 0. + + Arguments: + + This - Indicates the calling context. + + ExtendedVerification - Indicates that the driver may perform a more exhaustive + verification operation of the device during reset. + + Returns: + + EFI_SUCCESS + The reset operation succeeds. + + EFI_DEVICE_ERROR + The terminal is not functioning correctly or the serial port reset fails. + +--*/ +{ + EFI_STATUS Status; + TERMINAL_DEV *TerminalDevice; + + TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This); + + // + // Perform a more exhaustive reset by resetting the serial port. + // + if (ExtendedVerification) { + // + // Report progress code here + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_RESET, + TerminalDevice->DevicePath + ); + + Status = TerminalDevice->SerialIo->Reset (TerminalDevice->SerialIo); + if (EFI_ERROR (Status)) { + // + // Report error code here + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR, + TerminalDevice->DevicePath + ); + + return Status; + } + } + + This->SetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BACKGROUND_BLACK)); + + Status = This->SetMode (This, 0); + + return Status; +} + +EFI_STATUS +EFIAPI +TerminalConOutOutputString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString(). + The Unicode string will be converted to terminal expressible data stream + and send to terminal via serial port. + + + Arguments: + + This - Indicates the calling context. + + WString - The Null-terminated Unicode string to be displayed on + the terminal screen. + + Returns: + + EFI_SUCCESS + The string is output successfully. + + EFI_DEVICE_ERROR + The serial port fails to send the string out. + + EFI_WARN_UNKNOWN_GLYPH + Indicates that some of the characters in the Unicode string could not + be rendered and are skipped. + + EFI_UNSUPPORTED + +--*/ +{ + TERMINAL_DEV *TerminalDevice; + EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode; + UINTN MaxColumn; + UINTN MaxRow; + UINTN Length; + UTF8_CHAR Utf8Char; + CHAR8 GraphicChar; + CHAR8 AsciiChar; + EFI_STATUS Status; + UINT8 ValidBytes; + // + // flag used to indicate whether condition happens which will cause + // return EFI_WARN_UNKNOWN_GLYPH + // + BOOLEAN Warning; + + ValidBytes = 0; + Warning = FALSE; + + // + // get Terminal device data structure pointer. + // + TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This); + + // + // get current display mode + // Terminal driver only support mode 0 + // + Mode = This->Mode; + if (Mode->Mode != 0) { + return EFI_UNSUPPORTED; + } + + This->QueryMode ( + This, + Mode->Mode, + &MaxColumn, + &MaxRow + ); + + for (; *WString != CHAR_NULL; WString++) { + + switch (TerminalDevice->TerminalType) { + + case PcAnsiType: + case VT100Type: + case VT100PlusType: + + if (!TerminalIsValidTextGraphics (*WString, &GraphicChar, &AsciiChar)) { + // + // If it's not a graphic character convert Unicode to ASCII. + // + GraphicChar = (CHAR8) *WString; + + if (!(TerminalIsValidAscii (GraphicChar) || TerminalIsValidEfiCntlChar (GraphicChar))) { + // + // when this driver use the OutputString to output control string, + // TerminalDevice->OutputEscChar is set to let the Esc char + // to be output to the terminal emulation software. + // + if ((GraphicChar == 27) && TerminalDevice->OutputEscChar) { + GraphicChar = 27; + } else { + GraphicChar = '?'; + Warning = TRUE; + } + } + + AsciiChar = GraphicChar; + + } + + if (TerminalDevice->TerminalType != PcAnsiType) { + GraphicChar = AsciiChar; + } + + Length = 1; + + Status = TerminalDevice->SerialIo->Write ( + TerminalDevice->SerialIo, + &Length, + &GraphicChar + ); + + if (EFI_ERROR (Status)) { + goto OutputError; + } + + break; + + case VTUTF8Type: + UnicodeToUtf8 (*WString, &Utf8Char, &ValidBytes); + Length = ValidBytes; + Status = TerminalDevice->SerialIo->Write ( + TerminalDevice->SerialIo, + &Length, + (UINT8 *) &Utf8Char + ); + if (EFI_ERROR (Status)) { + goto OutputError; + } + break; + } + // + // Update cursor position. + // + switch (*WString) { + + case CHAR_BACKSPACE: + if (Mode->CursorColumn > 0) { + Mode->CursorColumn--; + } + break; + + case CHAR_LINEFEED: + if (Mode->CursorRow < (INT32) (MaxRow - 1)) { + Mode->CursorRow++; + } + break; + + case CHAR_CARRIAGE_RETURN: + Mode->CursorColumn = 0; + break; + + default: + if (Mode->CursorColumn < (INT32) (MaxColumn - 1)) { + + Mode->CursorColumn++; + + } else { + + Mode->CursorColumn = 0; + if (Mode->CursorRow < (INT32) (MaxRow - 1)) { + Mode->CursorRow++; + } + + } + break; + + }; + + } + + if (Warning) { + return EFI_WARN_UNKNOWN_GLYPH; + } + + return EFI_SUCCESS; + +OutputError: + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_OUTPUT_ERROR, + TerminalDevice->DevicePath + ); + + return EFI_DEVICE_ERROR; +} + +EFI_STATUS +EFIAPI +TerminalConOutTestString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.TestString(). + If one of the characters in the *Wstring is + neither valid Unicode drawing characters, + not ASCII code, then this function will return + EFI_UNSUPPORTED. + + + Arguments: + + This - Indicates the calling context. + + WString - The Null-terminated Unicode string to be tested. + + Returns: + + EFI_SUCCESS + The terminal is capable of rendering the output string. + + EFI_UNSUPPORTED + Some of the characters in the Unicode string cannot be rendered. + +--*/ +{ + TERMINAL_DEV *TerminalDevice; + EFI_STATUS Status; + + // + // get Terminal device data structure pointer. + // + TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This); + + switch (TerminalDevice->TerminalType) { + + case PcAnsiType: + case VT100Type: + case VT100PlusType: + Status = AnsiTestString (TerminalDevice, WString); + break; + + case VTUTF8Type: + Status = VTUTF8TestString (TerminalDevice, WString); + break; + + default: + Status = EFI_UNSUPPORTED; + break; + } + + return Status; +} + +EFI_STATUS +EFIAPI +TerminalConOutQueryMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.QueryMode(). + It returns information for an available text mode + that the terminal supports. + In this driver, we only support text mode 80x25, which is + defined as mode 0. + + + Arguments: + + *This + Indicates the calling context. + + ModeNumber + The mode number to return information on. + + Columns + The returned columns of the requested mode. + + Rows + The returned rows of the requested mode. + + Returns: + + EFI_SUCCESS + The requested mode information is returned. + + EFI_UNSUPPORTED + The mode number is not valid. + + EFI_DEVICE_ERROR + +--*/ +{ + if (This->Mode->MaxMode > 1) { + return EFI_DEVICE_ERROR; + } + + if (ModeNumber == 0) { + + *Columns = MODE0_COLUMN_COUNT; + *Rows = MODE0_ROW_COUNT; + + return EFI_SUCCESS; + } + + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI +TerminalConOutSetMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_OUT.SetMode(). + Set the terminal to a specified display mode. + In this driver, we only support mode 0. + + Arguments: + + This + Indicates the calling context. + + ModeNumber + The text mode to set. + + Returns: + + EFI_SUCCESS + The requested text mode is set. + + EFI_DEVICE_ERROR + The requested text mode cannot be set because of serial device error. + + EFI_UNSUPPORTED + The text mode number is not valid. + +--*/ +{ + EFI_STATUS Status; + TERMINAL_DEV *TerminalDevice; + + // + // get Terminal device data structure pointer. + // + TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This); + + if (ModeNumber != 0) { + return EFI_UNSUPPORTED; + } + + This->Mode->Mode = 0; + + This->ClearScreen (This); + + TerminalDevice->OutputEscChar = TRUE; + Status = This->OutputString (This, mSetModeString); + TerminalDevice->OutputEscChar = FALSE; + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + This->Mode->Mode = 0; + + Status = This->ClearScreen (This); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +EFIAPI +TerminalConOutSetAttribute ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Attribute + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute(). + + Arguments: + + This + Indicates the calling context. + + Attribute + The attribute to set. Only bit0..6 are valid, all other bits + are undefined and must be zero. + + Returns: + + EFI_SUCCESS + The requested attribute is set. + + EFI_DEVICE_ERROR + The requested attribute cannot be set due to serial port error. + + EFI_UNSUPPORTED + The attribute requested is not defined by EFI spec. + +--*/ +{ + UINT8 ForegroundControl; + UINT8 BackgroundControl; + UINT8 BrightControl; + INT32 SavedColumn; + INT32 SavedRow; + EFI_STATUS Status; + TERMINAL_DEV *TerminalDevice; + + SavedColumn = 0; + SavedRow = 0; + + // + // get Terminal device data structure pointer. + // + TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This); + + // + // only the bit0..6 of the Attribute is valid + // + if ((Attribute | 0x7f) != 0x7f) { + return EFI_UNSUPPORTED; + } + // + // convert Attribute value to terminal emulator + // understandable foreground color + // + switch (Attribute & 0x07) { + + case EFI_BLACK: + ForegroundControl = 30; + break; + + case EFI_BLUE: + ForegroundControl = 34; + break; + + case EFI_GREEN: + ForegroundControl = 32; + break; + + case EFI_CYAN: + ForegroundControl = 36; + break; + + case EFI_RED: + ForegroundControl = 31; + break; + + case EFI_MAGENTA: + ForegroundControl = 35; + break; + + case EFI_BROWN: + ForegroundControl = 33; + break; + + default: + + case EFI_LIGHTGRAY: + ForegroundControl = 37; + break; + + } + // + // bit4 of the Attribute indicates bright control + // of terminal emulator. + // + BrightControl = (UINT8) ((Attribute >> 3) & 1); + + // + // convert Attribute value to terminal emulator + // understandable background color. + // + switch ((Attribute >> 4) & 0x07) { + + case EFI_BLACK: + BackgroundControl = 40; + break; + + case EFI_BLUE: + BackgroundControl = 44; + break; + + case EFI_GREEN: + BackgroundControl = 42; + break; + + case EFI_CYAN: + BackgroundControl = 46; + break; + + case EFI_RED: + BackgroundControl = 41; + break; + + case EFI_MAGENTA: + BackgroundControl = 45; + break; + + case EFI_BROWN: + BackgroundControl = 43; + break; + + default: + + case EFI_LIGHTGRAY: + BackgroundControl = 47; + break; + } + // + // terminal emulator's control sequence to set attributes + // + mSetAttributeString[BRIGHT_CONTROL_OFFSET] = (CHAR16) ('0' + BrightControl); + mSetAttributeString[FOREGROUND_CONTROL_OFFSET + 0] = (CHAR16) ('0' + (ForegroundControl / 10)); + mSetAttributeString[FOREGROUND_CONTROL_OFFSET + 1] = (CHAR16) ('0' + (ForegroundControl % 10)); + mSetAttributeString[BACKGROUND_CONTROL_OFFSET + 0] = (CHAR16) ('0' + (BackgroundControl / 10)); + mSetAttributeString[BACKGROUND_CONTROL_OFFSET + 1] = (CHAR16) ('0' + (BackgroundControl % 10)); + + // + // save current column and row + // for future scrolling back use. + // + SavedColumn = This->Mode->CursorColumn; + SavedRow = This->Mode->CursorRow; + + TerminalDevice->OutputEscChar = TRUE; + Status = This->OutputString (This, mSetAttributeString); + TerminalDevice->OutputEscChar = FALSE; + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // scroll back to saved cursor position. + // + This->Mode->CursorColumn = SavedColumn; + This->Mode->CursorRow = SavedRow; + + This->Mode->Attribute = (INT32) Attribute; + + return EFI_SUCCESS; + +} + +EFI_STATUS +EFIAPI +TerminalConOutClearScreen ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.ClearScreen(). + It clears the ANSI terminal's display to the + currently selected background color. + + + Arguments: + + This + Indicates the calling context. + + Returns: + + EFI_SUCCESS + The operation completed successfully. + + EFI_DEVICE_ERROR + The terminal screen cannot be cleared due to serial port error. + + EFI_UNSUPPORTED + The terminal is not in a valid display mode. + +--*/ +{ + EFI_STATUS Status; + TERMINAL_DEV *TerminalDevice; + + TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This); + + // + // control sequence for clear screen request + // + TerminalDevice->OutputEscChar = TRUE; + Status = This->OutputString (This, mClearScreenString); + TerminalDevice->OutputEscChar = FALSE; + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Status = This->SetCursorPosition (This, 0, 0); + + return Status; +} + +EFI_STATUS +EFIAPI +TerminalConOutSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetCursorPosition(). + + Arguments: + + This + Indicates the calling context. + + Column + The row to set cursor to. + + Row + The column to set cursor to. + + Returns: + + EFI_SUCCESS + The operation completed successfully. + + EFI_DEVICE_ERROR + The request fails due to serial port error. + + EFI_UNSUPPORTED + The terminal is not in a valid text mode, or the cursor position + is invalid for current mode. + +--*/ +{ + EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode; + UINTN MaxColumn; + UINTN MaxRow; + EFI_STATUS Status; + TERMINAL_DEV *TerminalDevice; + + TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This); + + // + // get current mode + // + Mode = This->Mode; + + // + // get geometry of current mode + // + Status = This->QueryMode ( + This, + Mode->Mode, + &MaxColumn, + &MaxRow + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + if (Column >= MaxColumn || Row >= MaxRow) { + return EFI_UNSUPPORTED; + } + // + // control sequence to move the cursor + // + mSetCursorPositionString[ROW_OFFSET + 0] = (CHAR16) ('0' + ((Row + 1) / 10)); + mSetCursorPositionString[ROW_OFFSET + 1] = (CHAR16) ('0' + ((Row + 1) % 10)); + mSetCursorPositionString[COLUMN_OFFSET + 0] = (CHAR16) ('0' + ((Column + 1) / 10)); + mSetCursorPositionString[COLUMN_OFFSET + 1] = (CHAR16) ('0' + ((Column + 1) % 10)); + + TerminalDevice->OutputEscChar = TRUE; + Status = This->OutputString (This, mSetCursorPositionString); + TerminalDevice->OutputEscChar = FALSE; + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // update current cursor position + // in the Mode data structure. + // + Mode->CursorColumn = (INT32) Column; + Mode->CursorRow = (INT32) Row; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +TerminalConOutEnableCursor ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN Visible + ) +/*++ + Routine Description: + + Implements SIMPLE_TEXT_OUTPUT.EnableCursor(). + In this driver, the cursor cannot be hidden. + + Arguments: + + This + 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. + + EFI_UNSUPPORTED + The terminal does not support cursor hidden. + +--*/ +{ + if (!Visible) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +BOOLEAN +TerminalIsValidTextGraphics ( + IN CHAR16 Graphic, + OUT CHAR8 *PcAnsi, OPTIONAL + OUT CHAR8 *Ascii OPTIONAL + ) +/*++ + +Routine Description: + + Detects if a Unicode char is for Box Drawing text graphics. + +Arguments: + + Graphic - Unicode char to test. + + PcAnsi - Optional pointer to return PCANSI equivalent of Graphic. + + Ascii - Optional pointer to return ASCII equivalent of Graphic. + +Returns: + + TRUE if Graphic is a supported Unicode Box Drawing character. + +--*/ +{ + UNICODE_TO_CHAR *Table; + + if ((((Graphic & 0xff00) != 0x2500) && ((Graphic & 0xff00) != 0x2100))) { + // + // Unicode drawing code charts are all in the 0x25xx range, + // arrows are 0x21xx + // + return FALSE; + } + + for (Table = UnicodeToPcAnsiOrAscii; Table->Unicode != 0x0000; Table++) { + if (Graphic == Table->Unicode) { + if (PcAnsi != NULL) { + *PcAnsi = Table->PcAnsi; + } + + if (Ascii != NULL) { + *Ascii = Table->Ascii; + } + + return TRUE; + } + } + + return FALSE; +} + +BOOLEAN +TerminalIsValidAscii ( + IN CHAR16 Ascii + ) +{ + // + // valid ascii code lies in the extent of 0x20 ~ 0x7f + // + if ((Ascii >= 0x20) && (Ascii <= 0x7f)) { + return TRUE; + } + + return FALSE; +} + +BOOLEAN +TerminalIsValidEfiCntlChar ( + IN CHAR16 CharC + ) +{ + // + // only support four control characters. + // + if (CharC == CHAR_NULL || + CharC == CHAR_BACKSPACE || + CharC == CHAR_LINEFEED || + CharC == CHAR_CARRIAGE_RETURN || + CharC == CHAR_TAB + ) { + return TRUE; + } + + return FALSE; +} diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/ansi.c b/MdeModulePkg/Universal/Console/TerminalDxe/ansi.c new file mode 100644 index 0000000000..c3ebe245bf --- /dev/null +++ b/MdeModulePkg/Universal/Console/TerminalDxe/ansi.c @@ -0,0 +1,73 @@ +/*++ + +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: + + ansi.c + +Abstract: + + +Revision History +--*/ + + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#include "Terminal.h" + +VOID +AnsiRawDataToUnicode ( + IN TERMINAL_DEV *TerminalDevice + ) +{ + UINT8 RawData; + + // + // pop the raw data out from the raw fifo, + // and translate it into unicode, then push + // the unicode into unicode fifo, until the raw fifo is empty. + // + while (!IsRawFiFoEmpty (TerminalDevice)) { + + RawFiFoRemoveOneKey (TerminalDevice, &RawData); + + UnicodeFiFoInsertOneKey (TerminalDevice, (UINT16) RawData); + } +} + +EFI_STATUS +AnsiTestString ( + IN TERMINAL_DEV *TerminalDevice, + IN CHAR16 *WString + ) +{ + CHAR8 GraphicChar; + + // + // support three kind of character: + // valid ascii, valid efi control char, valid text graphics. + // + for (; *WString != CHAR_NULL; WString++) { + + if ( !(TerminalIsValidAscii (*WString) || + TerminalIsValidEfiCntlChar (*WString) || + TerminalIsValidTextGraphics (*WString, &GraphicChar, NULL) )) { + + return EFI_UNSUPPORTED; + } + } + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/vtutf8.c b/MdeModulePkg/Universal/Console/TerminalDxe/vtutf8.c new file mode 100644 index 0000000000..72e0920c8a --- /dev/null +++ b/MdeModulePkg/Universal/Console/TerminalDxe/vtutf8.c @@ -0,0 +1,275 @@ +/*++ + +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: + + vtutf8.c + +Abstract: + + +Revision History +--*/ + + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#include "Terminal.h" + +VOID +VTUTF8RawDataToUnicode ( + IN TERMINAL_DEV *TerminalDevice + ) +{ + UTF8_CHAR Utf8Char; + UINT8 ValidBytes; + UINT16 UnicodeChar; + + ValidBytes = 0; + // + // pop the raw data out from the raw fifo, + // and translate it into unicode, then push + // the unicode into unicode fifo, until the raw fifo is empty. + // + while (!IsRawFiFoEmpty (TerminalDevice)) { + + GetOneValidUtf8Char (TerminalDevice, &Utf8Char, &ValidBytes); + + if (ValidBytes < 1 || ValidBytes > 3) { + continue; + } + + Utf8ToUnicode (Utf8Char, ValidBytes, (CHAR16 *) &UnicodeChar); + + UnicodeFiFoInsertOneKey (TerminalDevice, UnicodeChar); + } +} + +VOID +GetOneValidUtf8Char ( + IN TERMINAL_DEV *Utf8Device, + OUT UTF8_CHAR *Utf8Char, + OUT UINT8 *ValidBytes + ) +{ + UINT8 Temp; + UINT8 Index; + BOOLEAN FetchFlag; + + Temp = 0; + Index = 0; + FetchFlag = TRUE; + + // + // if no valid Utf8 char is found in the RawFiFo, + // then *ValidBytes will be zero. + // + *ValidBytes = 0; + + while (!IsRawFiFoEmpty (Utf8Device)) { + + RawFiFoRemoveOneKey (Utf8Device, &Temp); + + switch (*ValidBytes) { + + case 0: + if ((Temp & 0x80) == 0) { + // + // one-byte utf8 char + // + *ValidBytes = 1; + + Utf8Char->Utf8_1 = Temp; + + FetchFlag = FALSE; + + } else if ((Temp & 0xe0) == 0xc0) { + // + // two-byte utf8 char + // + *ValidBytes = 2; + + Utf8Char->Utf8_2[1] = Temp; + + } else if ((Temp & 0xf0) == 0xe0) { + // + // three-byte utf8 char + // + *ValidBytes = 3; + + Utf8Char->Utf8_3[2] = Temp; + + Index++; + + } else { + // + // reset *ValidBytes to zero, let valid utf8 char search restart + // + *ValidBytes = 0; + } + + break; + + case 2: + if ((Temp & 0xc0) == 0x80) { + + Utf8Char->Utf8_2[0] = Temp; + + FetchFlag = FALSE; + + } else { + + *ValidBytes = 0; + } + break; + + case 3: + if ((Temp & 0xc0) == 0x80) { + + Utf8Char->Utf8_3[2 - Index] = Temp; + Index++; + if (Index == 3) { + FetchFlag = FALSE; + } + } else { + + *ValidBytes = 0; + Index = 0; + } + break; + + default: + break; + } + + if (!FetchFlag) { + break; + } + } + + return ; +} + +VOID +Utf8ToUnicode ( + IN UTF8_CHAR Utf8Char, + IN UINT8 ValidBytes, + OUT CHAR16 *UnicodeChar + ) +{ + UINT8 UnicodeByte0; + UINT8 UnicodeByte1; + UINT8 Byte0; + UINT8 Byte1; + UINT8 Byte2; + + *UnicodeChar = 0; + + // + // translate utf8 code to unicode, in terminal standard, + // up to 3 bytes utf8 code is supported. + // + switch (ValidBytes) { + case 1: + // + // one-byte utf8 code + // + *UnicodeChar = (UINT16) Utf8Char.Utf8_1; + break; + + case 2: + // + // two-byte utf8 code + // + Byte0 = Utf8Char.Utf8_2[0]; + Byte1 = Utf8Char.Utf8_2[1]; + + UnicodeByte0 = (UINT8) ((Byte1 << 6) | (Byte0 & 0x3f)); + UnicodeByte1 = (UINT8) ((Byte1 >> 2) & 0x07); + *UnicodeChar = (UINT16) (UnicodeByte0 | (UnicodeByte1 << 8)); + break; + + case 3: + // + // three-byte utf8 code + // + Byte0 = Utf8Char.Utf8_3[0]; + Byte1 = Utf8Char.Utf8_3[1]; + Byte2 = Utf8Char.Utf8_3[2]; + + UnicodeByte0 = (UINT8) ((Byte1 << 6) | (Byte0 & 0x3f)); + UnicodeByte1 = (UINT8) ((Byte2 << 4) | ((Byte1 >> 2) & 0x0f)); + *UnicodeChar = (UINT16) (UnicodeByte0 | (UnicodeByte1 << 8)); + + default: + break; + } + + return ; +} + +VOID +UnicodeToUtf8 ( + IN CHAR16 Unicode, + OUT UTF8_CHAR *Utf8Char, + OUT UINT8 *ValidBytes + ) +{ + UINT8 UnicodeByte0; + UINT8 UnicodeByte1; + // + // translate unicode to utf8 code + // + UnicodeByte0 = (UINT8) Unicode; + UnicodeByte1 = (UINT8) (Unicode >> 8); + + if (Unicode < 0x0080) { + + Utf8Char->Utf8_1 = (UINT8) (UnicodeByte0 & 0x7f); + *ValidBytes = 1; + + } else if (Unicode < 0x0800) { + // + // byte sequence: high -> low + // Utf8_2[0], Utf8_2[1] + // + Utf8Char->Utf8_2[1] = (UINT8) ((UnicodeByte0 & 0x3f) + 0x80); + Utf8Char->Utf8_2[0] = (UINT8) ((((UnicodeByte1 << 2) + (UnicodeByte0 >> 6)) & 0x1f) + 0xc0); + + *ValidBytes = 2; + + } else { + // + // byte sequence: high -> low + // Utf8_3[0], Utf8_3[1], Utf8_3[2] + // + Utf8Char->Utf8_3[2] = (UINT8) ((UnicodeByte0 & 0x3f) + 0x80); + Utf8Char->Utf8_3[1] = (UINT8) ((((UnicodeByte1 << 2) + (UnicodeByte0 >> 6)) & 0x3f) + 0x80); + Utf8Char->Utf8_3[0] = (UINT8) (((UnicodeByte1 >> 4) & 0x0f) + 0xe0); + + *ValidBytes = 3; + } +} + +EFI_STATUS +VTUTF8TestString ( + IN TERMINAL_DEV *TerminalDevice, + IN CHAR16 *WString + ) +{ + // + // to utf8, all kind of characters are supported. + // + return EFI_SUCCESS; +} -- cgit v1.2.3