From 02b7bcf9ce11571fe141871a5edcc01396473108 Mon Sep 17 00:00:00 2001 From: niruiyu Date: Sat, 8 Oct 2011 02:09:50 +0000 Subject: MdeModulePkg: Fix TerminalDxe FIFO Data Loss Fixes a Terminal FIFO full issue that caused data to be lost. The Unicode and EFI Key FIFOs are now checked to make sure they have spaces before pushing another entry. Signed-off-by: eugenecohen Reviewed-by: niruiyu git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12512 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Universal/Console/TerminalDxe/Ansi.c | 158 +- .../Universal/Console/TerminalDxe/TerminalConIn.c | 3140 ++++++++++---------- .../Universal/Console/TerminalDxe/Vtutf8.c | 656 ++-- 3 files changed, 1978 insertions(+), 1976 deletions(-) diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/Ansi.c b/MdeModulePkg/Universal/Console/TerminalDxe/Ansi.c index 4ebd7c9f46..4f84cc09ce 100644 --- a/MdeModulePkg/Universal/Console/TerminalDxe/Ansi.c +++ b/MdeModulePkg/Universal/Console/TerminalDxe/Ansi.c @@ -1,79 +1,79 @@ -/** @file - Implementation of translation upon PC ANSI. - -Copyright (c) 2006 - 2008, 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 "Terminal.h" - -/** - Translate all raw data in the Raw FIFO into unicode, and insert - them into Unicode FIFO. - - @param TerminalDevice The terminal device. - -**/ -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); - } -} - -/** - Check if input string is valid Ascii string, valid EFI control characters - or valid text graphics. - - @param TerminalDevice The terminal device. - @param WString The input string. - - @retval EFI_UNSUPPORTED If not all input characters are valid. - @retval EFI_SUCCESS If all input characters are valid. - -**/ -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; -} +/** @file + Implementation of translation upon PC ANSI. + +Copyright (c) 2006 - 2008, 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 "Terminal.h" + +/** + Translate all raw data in the Raw FIFO into unicode, and insert + them into Unicode FIFO. + + @param TerminalDevice The terminal device. + +**/ +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) && !IsUnicodeFiFoFull(TerminalDevice) ) { + + RawFiFoRemoveOneKey (TerminalDevice, &RawData); + + UnicodeFiFoInsertOneKey (TerminalDevice, (UINT16) RawData); + } +} + +/** + Check if input string is valid Ascii string, valid EFI control characters + or valid text graphics. + + @param TerminalDevice The terminal device. + @param WString The input string. + + @retval EFI_UNSUPPORTED If not all input characters are valid. + @retval EFI_SUCCESS If all input characters are valid. + +**/ +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/TerminalConIn.c b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c index b5dbaf9280..662cd5682f 100644 --- a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c +++ b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c @@ -1,1569 +1,1571 @@ -/** @file - Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol. - -Copyright (c) 2006 - 2011, 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 "Terminal.h" - - -/** - Reads the next keystroke from the input device. The WaitForKey Event can - be used to test for existence of a keystroke via WaitForEvent () call. - - @param TerminalDevice Terminal driver private structure - @param KeyData A pointer to a buffer that is filled in with the - keystroke state data for the key that was - pressed. - - @retval EFI_SUCCESS The keystroke information was returned. - @retval EFI_NOT_READY There was no keystroke data available. - @retval EFI_INVALID_PARAMETER KeyData is NULL. - -**/ -EFI_STATUS -ReadKeyStrokeWorker ( - IN TERMINAL_DEV *TerminalDevice, - OUT EFI_KEY_DATA *KeyData - ) -{ - if (KeyData == NULL) { - return EFI_INVALID_PARAMETER; - } - - if (!EfiKeyFiFoRemoveOneKey (TerminalDevice, &KeyData->Key)) { - return EFI_NOT_READY; - } - - KeyData->KeyState.KeyShiftState = 0; - KeyData->KeyState.KeyToggleState = 0; - - - return EFI_SUCCESS; - -} - -/** - Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset(). - This driver only perform dependent serial device reset regardless of - the value of ExtendeVerification - - @param This Indicates the calling context. - @param ExtendedVerification Skip by this driver. - - @retval EFI_SUCCESS The reset operation succeeds. - @retval EFI_DEVICE_ERROR The dependent serial port reset fails. - -**/ -EFI_STATUS -EFIAPI -TerminalConInReset ( - IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, - IN BOOLEAN ExtendedVerification - ) -{ - 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); - - // - // Make all the internal buffer empty for keys - // - TerminalDevice->RawFiFo->Head = TerminalDevice->RawFiFo->Tail; - TerminalDevice->UnicodeFiFo->Head = TerminalDevice->UnicodeFiFo->Tail; - TerminalDevice->EfiKeyFiFo->Head = TerminalDevice->EfiKeyFiFo->Tail; - - if (EFI_ERROR (Status)) { - 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; -} - -/** - Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke(). - - @param This Indicates the calling context. - @param Key A pointer to a buffer that is filled in with the - keystroke information for the key that was sent - from terminal. - - @retval EFI_SUCCESS The keystroke information is returned successfully. - @retval EFI_NOT_READY There is no keystroke data available. - @retval EFI_DEVICE_ERROR The dependent serial device encounters error. - -**/ -EFI_STATUS -EFIAPI -TerminalConInReadKeyStroke ( - IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, - OUT EFI_INPUT_KEY *Key - ) -{ - TERMINAL_DEV *TerminalDevice; - EFI_STATUS Status; - EFI_KEY_DATA KeyData; - - // - // get TERMINAL_DEV from "This" parameter. - // - TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This); - - Status = ReadKeyStrokeWorker (TerminalDevice, &KeyData); - if (EFI_ERROR (Status)) { - return Status; - } - - CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY)); - - return EFI_SUCCESS; - -} - -/** - Check if the key already has been registered. - - If both RegsiteredData and InputData is NULL, then ASSERT(). - - @param RegsiteredData A pointer to a buffer that is filled in with the - keystroke state data for the key that was - registered. - @param InputData A pointer to a buffer that is filled in with the - keystroke state data for the key that was - pressed. - - @retval TRUE Key be pressed matches a registered key. - @retval FLASE Match failed. - -**/ -BOOLEAN -IsKeyRegistered ( - IN EFI_KEY_DATA *RegsiteredData, - IN EFI_KEY_DATA *InputData - ) -{ - ASSERT (RegsiteredData != NULL && InputData != NULL); - - if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) || - (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) { - return FALSE; - } - - return TRUE; -} - - - -/** - Event notification function for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event - Signal the event if there is key available - - @param Event Indicates the event that invoke this function. - @param Context Indicates the calling context. - -**/ -VOID -EFIAPI -TerminalConInWaitForKeyEx ( - IN EFI_EVENT Event, - IN VOID *Context - ) -{ - TerminalConInWaitForKey (Event, Context); -} - -// -// Simple Text Input Ex protocol functions -// - -/** - Reset the input device and optionally run diagnostics - - @param This Protocol instance pointer. - @param ExtendedVerification Driver may perform diagnostics on reset. - - @retval EFI_SUCCESS The device was reset. - @retval EFI_DEVICE_ERROR The device is not functioning properly and could - not be reset. - -**/ -EFI_STATUS -EFIAPI -TerminalConInResetEx ( - IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - IN BOOLEAN ExtendedVerification - ) -{ - EFI_STATUS Status; - TERMINAL_DEV *TerminalDevice; - - TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This); - - Status = TerminalDevice->SimpleInput.Reset (&TerminalDevice->SimpleInput, ExtendedVerification); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - return EFI_SUCCESS; - -} - - -/** - Reads the next keystroke from the input device. The WaitForKey Event can - be used to test for existence of a keystroke via WaitForEvent () call. - - @param This Protocol instance pointer. - @param KeyData A pointer to a buffer that is filled in with the - keystroke state data for the key that was - pressed. - - @retval EFI_SUCCESS The keystroke information was returned. - @retval EFI_NOT_READY There was no keystroke data available. - @retval EFI_DEVICE_ERROR The keystroke information was not returned due - to hardware errors. - @retval EFI_INVALID_PARAMETER KeyData is NULL. - -**/ -EFI_STATUS -EFIAPI -TerminalConInReadKeyStrokeEx ( - IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - OUT EFI_KEY_DATA *KeyData - ) -{ - TERMINAL_DEV *TerminalDevice; - - if (KeyData == NULL) { - return EFI_INVALID_PARAMETER; - } - - TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This); - - return ReadKeyStrokeWorker (TerminalDevice, KeyData); - -} - - -/** - Set certain state for the input device. - - @param This Protocol instance pointer. - @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the - state for the input device. - - @retval EFI_SUCCESS The device state was set successfully. - @retval EFI_DEVICE_ERROR The device is not functioning correctly and - could not have the setting adjusted. - @retval EFI_UNSUPPORTED The device does not have the ability to set its - state. - @retval EFI_INVALID_PARAMETER KeyToggleState is NULL. - -**/ -EFI_STATUS -EFIAPI -TerminalConInSetState ( - IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - IN EFI_KEY_TOGGLE_STATE *KeyToggleState - ) -{ - if (KeyToggleState == NULL) { - return EFI_INVALID_PARAMETER; - } - - return EFI_SUCCESS; -} - - -/** - Register a notification function for a particular keystroke for the input device. - - @param This Protocol instance pointer. - @param KeyData A pointer to a buffer that is filled in with the - keystroke information data for the key that was - pressed. - @param KeyNotificationFunction Points to the function to be called when the key - sequence is typed specified by KeyData. - @param NotifyHandle Points to the unique handle assigned to the - registered notification. - - @retval EFI_SUCCESS The notification function was registered - successfully. - @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data - structures. - @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL. - -**/ -EFI_STATUS -EFIAPI -TerminalConInRegisterKeyNotify ( - IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - IN EFI_KEY_DATA *KeyData, - IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, - OUT EFI_HANDLE *NotifyHandle - ) -{ - TERMINAL_DEV *TerminalDevice; - TERMINAL_CONSOLE_IN_EX_NOTIFY *NewNotify; - LIST_ENTRY *Link; - LIST_ENTRY *NotifyList; - TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; - - if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) { - return EFI_INVALID_PARAMETER; - } - - TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This); - - // - // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered. - // - NotifyList = &TerminalDevice->NotifyList; - for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) { - CurrentNotify = CR ( - Link, - TERMINAL_CONSOLE_IN_EX_NOTIFY, - NotifyEntry, - TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE - ); - if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { - if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { - *NotifyHandle = CurrentNotify->NotifyHandle; - return EFI_SUCCESS; - } - } - } - - // - // Allocate resource to save the notification function - // - NewNotify = (TERMINAL_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (TERMINAL_CONSOLE_IN_EX_NOTIFY)); - if (NewNotify == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - NewNotify->Signature = TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE; - NewNotify->KeyNotificationFn = KeyNotificationFunction; - NewNotify->NotifyHandle = (EFI_HANDLE) NewNotify; - CopyMem (&NewNotify->KeyData, KeyData, sizeof (KeyData)); - InsertTailList (&TerminalDevice->NotifyList, &NewNotify->NotifyEntry); - - *NotifyHandle = NewNotify->NotifyHandle; - - return EFI_SUCCESS; -} - - -/** - Remove a registered notification function from a particular keystroke. - - @param This Protocol instance pointer. - @param NotificationHandle The handle of the notification function being - unregistered. - - @retval EFI_SUCCESS The notification function was unregistered - successfully. - @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid. - -**/ -EFI_STATUS -EFIAPI -TerminalConInUnregisterKeyNotify ( - IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - IN EFI_HANDLE NotificationHandle - ) -{ - TERMINAL_DEV *TerminalDevice; - LIST_ENTRY *Link; - TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; - LIST_ENTRY *NotifyList; - - if (NotificationHandle == NULL) { - return EFI_INVALID_PARAMETER; - } - - if (((TERMINAL_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature != TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE) { - return EFI_INVALID_PARAMETER; - } - - TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This); - - NotifyList = &TerminalDevice->NotifyList; - for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) { - CurrentNotify = CR ( - Link, - TERMINAL_CONSOLE_IN_EX_NOTIFY, - NotifyEntry, - TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE - ); - if (CurrentNotify->NotifyHandle == NotificationHandle) { - // - // Remove the notification function from NotifyList and free resources - // - RemoveEntryList (&CurrentNotify->NotifyEntry); - - gBS->FreePool (CurrentNotify); - return EFI_SUCCESS; - } - } - - // - // Can not find the matching entry in database. - // - return EFI_INVALID_PARAMETER; -} - -/** - Translate raw data into Unicode (according to different encode), and - translate Unicode into key information. (according to different standard). - - @param TerminalDevice Terminal driver private structure. - -**/ -VOID -TranslateRawDataToEfiKey ( - IN TERMINAL_DEV *TerminalDevice - ) -{ - 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; - } -} - -/** - Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event - Signal the event if there is key available - - @param Event Indicates the event that invoke this function. - @param Context Indicates the calling context. - -**/ -VOID -EFIAPI -TerminalConInWaitForKey ( - IN EFI_EVENT Event, - IN VOID *Context - ) -{ - // - // Someone is waiting on the keystroke event, if there's - // a key pending, signal the event - // - if (!IsEfiKeyFiFoEmpty ((TERMINAL_DEV *) Context)) { - - gBS->SignalEvent (Event); - } -} - -/** - Timer handler to poll the key from serial. - - @param Event Indicates the event that invoke this function. - @param Context Indicates the calling context. -**/ -VOID -EFIAPI -TerminalConInTimerHandler ( - IN EFI_EVENT Event, - IN VOID *Context - ) -{ - EFI_STATUS Status; - TERMINAL_DEV *TerminalDevice; - UINT8 Input; - EFI_SERIAL_IO_MODE *Mode; - EFI_SERIAL_IO_PROTOCOL *SerialIo; - UINTN SerialInTimeOut; - - TerminalDevice = (TERMINAL_DEV *) Context; - - SerialIo = TerminalDevice->SerialIo; - if (SerialIo == NULL) { - return ; - } - // - // 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) { - // - // According to BAUD rate to calculate the timeout value. - // - 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; - } - } - - // - // 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); -} - -/** - Get one key out of serial buffer. - - @param SerialIo Serial I/O protocol attached to the serial device. - @param Output The fetched key. - - @retval EFI_NOT_READY If serial buffer is empty. - @retval EFI_DEVICE_ERROR If reading serial buffer encounter error. - @retval EFI_SUCCESS If reading serial buffer successfully, put - the fetched key to the parameter output. - -**/ -EFI_STATUS -GetOneKeyFromSerial ( - EFI_SERIAL_IO_PROTOCOL *SerialIo, - UINT8 *Output - ) -{ - EFI_STATUS Status; - UINTN Size; - - Size = 1; - *Output = 0; - - // - // Read one key from serial I/O device. - // - Status = SerialIo->Read (SerialIo, &Size, Output); - - if (EFI_ERROR (Status)) { - - if (Status == EFI_TIMEOUT) { - return EFI_NOT_READY; - } - - return EFI_DEVICE_ERROR; - - } - - if (*Output == 0) { - return EFI_NOT_READY; - } - - return EFI_SUCCESS; -} - -/** - Insert one byte raw data into the Raw Data FIFO. - - @param TerminalDevice Terminal driver private structure. - @param Input The key will be input. - - @retval TRUE If insert successfully. - @retval FLASE If Raw Data buffer is full before key insertion, - and the key is lost. - -**/ -BOOLEAN -RawFiFoInsertOneKey ( - TERMINAL_DEV *TerminalDevice, - UINT8 Input - ) -{ - 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; -} - -/** - Remove one pre-fetched key out of the Raw Data FIFO. - - @param TerminalDevice Terminal driver private structure. - @param Output The key will be removed. - - @retval TRUE If insert successfully. - @retval FLASE If Raw Data FIFO buffer is empty before remove operation. - -**/ -BOOLEAN -RawFiFoRemoveOneKey ( - TERMINAL_DEV *TerminalDevice, - UINT8 *Output - ) -{ - 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; -} - -/** - Clarify whether Raw Data FIFO buffer is empty. - - @param TerminalDevice Terminal driver private structure - - @retval TRUE If Raw Data FIFO buffer is empty. - @retval FLASE If Raw Data FIFO buffer is not empty. - -**/ -BOOLEAN -IsRawFiFoEmpty ( - TERMINAL_DEV *TerminalDevice - ) -{ - if (TerminalDevice->RawFiFo->Head == TerminalDevice->RawFiFo->Tail) { - return TRUE; - } else { - return FALSE; - } -} - -/** - Clarify whether Raw Data FIFO buffer is full. - - @param TerminalDevice Terminal driver private structure - - @retval TRUE If Raw Data FIFO buffer is full. - @retval FLASE If Raw Data FIFO buffer is not full. - -**/ -BOOLEAN -IsRawFiFoFull ( - TERMINAL_DEV *TerminalDevice - ) -{ - 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; -} - -/** - Insert one pre-fetched key into the FIFO buffer. - - @param TerminalDevice Terminal driver private structure. - @param Key The key will be input. - - @retval TRUE If insert successfully. - @retval FLASE If FIFO buffer is full before key insertion, - and the key is lost. - -**/ -BOOLEAN -EfiKeyFiFoInsertOneKey ( - TERMINAL_DEV *TerminalDevice, - EFI_INPUT_KEY *Key - ) -{ - UINT8 Tail; - LIST_ENTRY *Link; - LIST_ENTRY *NotifyList; - TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; - EFI_KEY_DATA KeyData; - - Tail = TerminalDevice->EfiKeyFiFo->Tail; - - CopyMem (&KeyData.Key, Key, sizeof (EFI_INPUT_KEY)); - KeyData.KeyState.KeyShiftState = 0; - KeyData.KeyState.KeyToggleState = 0; - - // - // Invoke notification functions if exist - // - NotifyList = &TerminalDevice->NotifyList; - for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) { - CurrentNotify = CR ( - Link, - TERMINAL_CONSOLE_IN_EX_NOTIFY, - NotifyEntry, - TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE - ); - if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { - CurrentNotify->KeyNotificationFn (&KeyData); - } - } - if (IsEfiKeyFiFoFull (TerminalDevice)) { - // - // Efi Key FIFO is full - // - return FALSE; - } - - CopyMem (&TerminalDevice->EfiKeyFiFo->Data[Tail], Key, sizeof (EFI_INPUT_KEY)); - - TerminalDevice->EfiKeyFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1)); - - return TRUE; -} - -/** - Remove one pre-fetched key out of the FIFO buffer. - - @param TerminalDevice Terminal driver private structure. - @param Output The key will be removed. - - @retval TRUE If insert successfully. - @retval FLASE If FIFO buffer is empty before remove operation. - -**/ -BOOLEAN -EfiKeyFiFoRemoveOneKey ( - TERMINAL_DEV *TerminalDevice, - EFI_INPUT_KEY *Output - ) -{ - UINT8 Head; - - Head = TerminalDevice->EfiKeyFiFo->Head; - ASSERT (Head < FIFO_MAX_NUMBER + 1); - - 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; -} - -/** - Clarify whether FIFO buffer is empty. - - @param TerminalDevice Terminal driver private structure - - @retval TRUE If FIFO buffer is empty. - @retval FLASE If FIFO buffer is not empty. - -**/ -BOOLEAN -IsEfiKeyFiFoEmpty ( - TERMINAL_DEV *TerminalDevice - ) -{ - if (TerminalDevice->EfiKeyFiFo->Head == TerminalDevice->EfiKeyFiFo->Tail) { - return TRUE; - } else { - return FALSE; - } -} - -/** - Clarify whether FIFO buffer is full. - - @param TerminalDevice Terminal driver private structure - - @retval TRUE If FIFO buffer is full. - @retval FLASE If FIFO buffer is not full. - -**/ -BOOLEAN -IsEfiKeyFiFoFull ( - TERMINAL_DEV *TerminalDevice - ) -{ - UINT8 Tail; - UINT8 Head; - - Tail = TerminalDevice->EfiKeyFiFo->Tail; - Head = TerminalDevice->EfiKeyFiFo->Head; - - if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) { - - return TRUE; - } - - return FALSE; -} - -/** - Insert one pre-fetched key into the Unicode FIFO buffer. - - @param TerminalDevice Terminal driver private structure. - @param Input The key will be input. - - @retval TRUE If insert successfully. - @retval FLASE If Unicode FIFO buffer is full before key insertion, - and the key is lost. - -**/ -BOOLEAN -UnicodeFiFoInsertOneKey ( - TERMINAL_DEV *TerminalDevice, - UINT16 Input - ) -{ - UINT8 Tail; - - Tail = TerminalDevice->UnicodeFiFo->Tail; - ASSERT (Tail < FIFO_MAX_NUMBER + 1); - - - 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; -} - -/** - Remove one pre-fetched key out of the Unicode FIFO buffer. - - @param TerminalDevice Terminal driver private structure. - @param Output The key will be removed. - - @retval TRUE If insert successfully. - @retval FLASE If Unicode FIFO buffer is empty before remove operation. - -**/ -BOOLEAN -UnicodeFiFoRemoveOneKey ( - TERMINAL_DEV *TerminalDevice, - UINT16 *Output - ) -{ - UINT8 Head; - - Head = TerminalDevice->UnicodeFiFo->Head; - ASSERT (Head < FIFO_MAX_NUMBER + 1); - - 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; -} - -/** - Clarify whether Unicode FIFO buffer is empty. - - @param TerminalDevice Terminal driver private structure - - @retval TRUE If Unicode FIFO buffer is empty. - @retval FLASE If Unicode FIFO buffer is not empty. - -**/ -BOOLEAN -IsUnicodeFiFoEmpty ( - TERMINAL_DEV *TerminalDevice - ) -{ - if (TerminalDevice->UnicodeFiFo->Head == TerminalDevice->UnicodeFiFo->Tail) { - return TRUE; - } else { - return FALSE; - } -} - -/** - Clarify whether Unicode FIFO buffer is full. - - @param TerminalDevice Terminal driver private structure - - @retval TRUE If Unicode FIFO buffer is full. - @retval FLASE If Unicode FIFO buffer is not full. - -**/ -BOOLEAN -IsUnicodeFiFoFull ( - TERMINAL_DEV *TerminalDevice - ) -{ - UINT8 Tail; - UINT8 Head; - - Tail = TerminalDevice->UnicodeFiFo->Tail; - Head = TerminalDevice->UnicodeFiFo->Head; - - if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) { - - return TRUE; - } - - return FALSE; -} - -/** - Count Unicode FIFO buffer. - - @param TerminalDevice Terminal driver private structure - - @return The count in bytes of Unicode FIFO. - -**/ -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); - } -} - -/** - Update the Unicode characters from a terminal input device into EFI Keys FIFO. - - @param TerminalDevice The terminal device to use to translate raw input into EFI Keys - -**/ -VOID -UnicodeToEfiKeyFlushState ( - IN TERMINAL_DEV *TerminalDevice - ) -{ - EFI_INPUT_KEY Key; - UINT32 InputState; - - InputState = TerminalDevice->InputState; - - if ((InputState & INPUT_STATE_ESC) != 0) { - Key.ScanCode = SCAN_ESC; - Key.UnicodeChar = 0; - EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); - } - - if ((InputState & INPUT_STATE_CSI) != 0) { - Key.ScanCode = SCAN_NULL; - Key.UnicodeChar = CSI; - EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); - } - - if ((InputState & INPUT_STATE_LEFTOPENBRACKET) != 0) { - Key.ScanCode = SCAN_NULL; - Key.UnicodeChar = LEFTOPENBRACKET; - EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); - } - - if ((InputState & INPUT_STATE_O) != 0) { - Key.ScanCode = SCAN_NULL; - Key.UnicodeChar = 'O'; - EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); - } - - if ((InputState & INPUT_STATE_2) != 0) { - Key.ScanCode = SCAN_NULL; - Key.UnicodeChar = '2'; - EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); - } - - // - // Cancel the timer. - // - gBS->SetTimer ( - TerminalDevice->TwoSecondTimeOut, - TimerCancel, - 0 - ); - - TerminalDevice->InputState = INPUT_STATE_DEFAULT; -} - - -/** - 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 corresponding 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. - - Note: current implementation support terminal types include: PC ANSI, VT100+/VTUTF8, VT100. - The table below is not same with UEFI Spec 2.3 Appendix B Table 201(not support ANSI X3.64 / - DEC VT200-500 and extra support PC ANSI, VT100)since UEFI Table 201 is just an example. - - Symbols used in table below - =========================== - ESC = 0x1B - CSI = 0x9B - DEL = 0x7f - ^ = CTRL - - +=========+======+===========+==========+==========+ - | | EFI | UEFI 2.0 | | | - | | 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 | - | F11 | 0x15 | | ESC ! | | - | F12 | 0x16 | | ESC @ | | - +=========+======+===========+==========+==========+ - - Special Mappings - ================ - ESC R ESC r ESC R = Reset System - - @param TerminalDevice The terminal device to use to translate raw input into EFI Keys - -**/ -VOID -UnicodeToEfiKey ( - IN TERMINAL_DEV *TerminalDevice - ) -{ - 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 seconds 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 '!': - Key.ScanCode = SCAN_F11; - break; - case '@': - Key.ScanCode = SCAN_F12; - 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 (UnicodeChar == CSI) { - TerminalDevice->InputState = INPUT_STATE_CSI; - } - - 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); - } -} +/** @file + Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol. + +Copyright (c) 2006 - 2011, 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 "Terminal.h" + + +/** + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existence of a keystroke via WaitForEvent () call. + + @param TerminalDevice Terminal driver private structure + @param KeyData A pointer to a buffer that is filled in with the + keystroke state data for the key that was + pressed. + + @retval EFI_SUCCESS The keystroke information was returned. + @retval EFI_NOT_READY There was no keystroke data available. + @retval EFI_INVALID_PARAMETER KeyData is NULL. + +**/ +EFI_STATUS +ReadKeyStrokeWorker ( + IN TERMINAL_DEV *TerminalDevice, + OUT EFI_KEY_DATA *KeyData + ) +{ + if (KeyData == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (!EfiKeyFiFoRemoveOneKey (TerminalDevice, &KeyData->Key)) { + return EFI_NOT_READY; + } + + KeyData->KeyState.KeyShiftState = 0; + KeyData->KeyState.KeyToggleState = 0; + + + return EFI_SUCCESS; + +} + +/** + Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset(). + This driver only perform dependent serial device reset regardless of + the value of ExtendeVerification + + @param This Indicates the calling context. + @param ExtendedVerification Skip by this driver. + + @retval EFI_SUCCESS The reset operation succeeds. + @retval EFI_DEVICE_ERROR The dependent serial port reset fails. + +**/ +EFI_STATUS +EFIAPI +TerminalConInReset ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + 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); + + // + // Make all the internal buffer empty for keys + // + TerminalDevice->RawFiFo->Head = TerminalDevice->RawFiFo->Tail; + TerminalDevice->UnicodeFiFo->Head = TerminalDevice->UnicodeFiFo->Tail; + TerminalDevice->EfiKeyFiFo->Head = TerminalDevice->EfiKeyFiFo->Tail; + + if (EFI_ERROR (Status)) { + 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; +} + +/** + Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke(). + + @param This Indicates the calling context. + @param Key A pointer to a buffer that is filled in with the + keystroke information for the key that was sent + from terminal. + + @retval EFI_SUCCESS The keystroke information is returned successfully. + @retval EFI_NOT_READY There is no keystroke data available. + @retval EFI_DEVICE_ERROR The dependent serial device encounters error. + +**/ +EFI_STATUS +EFIAPI +TerminalConInReadKeyStroke ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ) +{ + TERMINAL_DEV *TerminalDevice; + EFI_STATUS Status; + EFI_KEY_DATA KeyData; + + // + // get TERMINAL_DEV from "This" parameter. + // + TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This); + + Status = ReadKeyStrokeWorker (TerminalDevice, &KeyData); + if (EFI_ERROR (Status)) { + return Status; + } + + CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY)); + + return EFI_SUCCESS; + +} + +/** + Check if the key already has been registered. + + If both RegsiteredData and InputData is NULL, then ASSERT(). + + @param RegsiteredData A pointer to a buffer that is filled in with the + keystroke state data for the key that was + registered. + @param InputData A pointer to a buffer that is filled in with the + keystroke state data for the key that was + pressed. + + @retval TRUE Key be pressed matches a registered key. + @retval FLASE Match failed. + +**/ +BOOLEAN +IsKeyRegistered ( + IN EFI_KEY_DATA *RegsiteredData, + IN EFI_KEY_DATA *InputData + ) +{ + ASSERT (RegsiteredData != NULL && InputData != NULL); + + if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) || + (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) { + return FALSE; + } + + return TRUE; +} + + + +/** + Event notification function for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event + Signal the event if there is key available + + @param Event Indicates the event that invoke this function. + @param Context Indicates the calling context. + +**/ +VOID +EFIAPI +TerminalConInWaitForKeyEx ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + TerminalConInWaitForKey (Event, Context); +} + +// +// Simple Text Input Ex protocol functions +// + +/** + Reset the input device and optionally run diagnostics + + @param This Protocol instance pointer. + @param ExtendedVerification Driver may perform diagnostics on reset. + + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The device is not functioning properly and could + not be reset. + +**/ +EFI_STATUS +EFIAPI +TerminalConInResetEx ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + EFI_STATUS Status; + TERMINAL_DEV *TerminalDevice; + + TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This); + + Status = TerminalDevice->SimpleInput.Reset (&TerminalDevice->SimpleInput, ExtendedVerification); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; + +} + + +/** + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existence of a keystroke via WaitForEvent () call. + + @param This Protocol instance pointer. + @param KeyData A pointer to a buffer that is filled in with the + keystroke state data for the key that was + pressed. + + @retval EFI_SUCCESS The keystroke information was returned. + @retval EFI_NOT_READY There was no keystroke data available. + @retval EFI_DEVICE_ERROR The keystroke information was not returned due + to hardware errors. + @retval EFI_INVALID_PARAMETER KeyData is NULL. + +**/ +EFI_STATUS +EFIAPI +TerminalConInReadKeyStrokeEx ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + OUT EFI_KEY_DATA *KeyData + ) +{ + TERMINAL_DEV *TerminalDevice; + + if (KeyData == NULL) { + return EFI_INVALID_PARAMETER; + } + + TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This); + + return ReadKeyStrokeWorker (TerminalDevice, KeyData); + +} + + +/** + Set certain state for the input device. + + @param This Protocol instance pointer. + @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the + state for the input device. + + @retval EFI_SUCCESS The device state was set successfully. + @retval EFI_DEVICE_ERROR The device is not functioning correctly and + could not have the setting adjusted. + @retval EFI_UNSUPPORTED The device does not have the ability to set its + state. + @retval EFI_INVALID_PARAMETER KeyToggleState is NULL. + +**/ +EFI_STATUS +EFIAPI +TerminalConInSetState ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_KEY_TOGGLE_STATE *KeyToggleState + ) +{ + if (KeyToggleState == NULL) { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + + +/** + Register a notification function for a particular keystroke for the input device. + + @param This Protocol instance pointer. + @param KeyData A pointer to a buffer that is filled in with the + keystroke information data for the key that was + pressed. + @param KeyNotificationFunction Points to the function to be called when the key + sequence is typed specified by KeyData. + @param NotifyHandle Points to the unique handle assigned to the + registered notification. + + @retval EFI_SUCCESS The notification function was registered + successfully. + @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data + structures. + @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL. + +**/ +EFI_STATUS +EFIAPI +TerminalConInRegisterKeyNotify ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_KEY_DATA *KeyData, + IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, + OUT EFI_HANDLE *NotifyHandle + ) +{ + TERMINAL_DEV *TerminalDevice; + TERMINAL_CONSOLE_IN_EX_NOTIFY *NewNotify; + LIST_ENTRY *Link; + LIST_ENTRY *NotifyList; + TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + + if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) { + return EFI_INVALID_PARAMETER; + } + + TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This); + + // + // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered. + // + NotifyList = &TerminalDevice->NotifyList; + for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) { + CurrentNotify = CR ( + Link, + TERMINAL_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE + ); + if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { + if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { + *NotifyHandle = CurrentNotify->NotifyHandle; + return EFI_SUCCESS; + } + } + } + + // + // Allocate resource to save the notification function + // + NewNotify = (TERMINAL_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (TERMINAL_CONSOLE_IN_EX_NOTIFY)); + if (NewNotify == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + NewNotify->Signature = TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE; + NewNotify->KeyNotificationFn = KeyNotificationFunction; + NewNotify->NotifyHandle = (EFI_HANDLE) NewNotify; + CopyMem (&NewNotify->KeyData, KeyData, sizeof (KeyData)); + InsertTailList (&TerminalDevice->NotifyList, &NewNotify->NotifyEntry); + + *NotifyHandle = NewNotify->NotifyHandle; + + return EFI_SUCCESS; +} + + +/** + Remove a registered notification function from a particular keystroke. + + @param This Protocol instance pointer. + @param NotificationHandle The handle of the notification function being + unregistered. + + @retval EFI_SUCCESS The notification function was unregistered + successfully. + @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid. + +**/ +EFI_STATUS +EFIAPI +TerminalConInUnregisterKeyNotify ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_HANDLE NotificationHandle + ) +{ + TERMINAL_DEV *TerminalDevice; + LIST_ENTRY *Link; + TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + LIST_ENTRY *NotifyList; + + if (NotificationHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (((TERMINAL_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature != TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This); + + NotifyList = &TerminalDevice->NotifyList; + for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) { + CurrentNotify = CR ( + Link, + TERMINAL_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE + ); + if (CurrentNotify->NotifyHandle == NotificationHandle) { + // + // Remove the notification function from NotifyList and free resources + // + RemoveEntryList (&CurrentNotify->NotifyEntry); + + gBS->FreePool (CurrentNotify); + return EFI_SUCCESS; + } + } + + // + // Can not find the matching entry in database. + // + return EFI_INVALID_PARAMETER; +} + +/** + Translate raw data into Unicode (according to different encode), and + translate Unicode into key information. (according to different standard). + + @param TerminalDevice Terminal driver private structure. + +**/ +VOID +TranslateRawDataToEfiKey ( + IN TERMINAL_DEV *TerminalDevice + ) +{ + 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; + } +} + +/** + Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event + Signal the event if there is key available + + @param Event Indicates the event that invoke this function. + @param Context Indicates the calling context. + +**/ +VOID +EFIAPI +TerminalConInWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Someone is waiting on the keystroke event, if there's + // a key pending, signal the event + // + if (!IsEfiKeyFiFoEmpty ((TERMINAL_DEV *) Context)) { + + gBS->SignalEvent (Event); + } +} + +/** + Timer handler to poll the key from serial. + + @param Event Indicates the event that invoke this function. + @param Context Indicates the calling context. +**/ +VOID +EFIAPI +TerminalConInTimerHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + TERMINAL_DEV *TerminalDevice; + UINT8 Input; + EFI_SERIAL_IO_MODE *Mode; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + UINTN SerialInTimeOut; + + TerminalDevice = (TERMINAL_DEV *) Context; + + SerialIo = TerminalDevice->SerialIo; + if (SerialIo == NULL) { + return ; + } + // + // 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) { + // + // According to BAUD rate to calculate the timeout value. + // + 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; + } + } + + // + // Fetch all the keys in the serial buffer, + // and insert the byte stream into RawFIFO. + // + while( !IsRawFiFoFull(TerminalDevice) ) { + + 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); + } + + // + // Translate all the raw data in RawFIFO into EFI Key, + // according to different terminal type supported. + // + TranslateRawDataToEfiKey (TerminalDevice); +} + +/** + Get one key out of serial buffer. + + @param SerialIo Serial I/O protocol attached to the serial device. + @param Output The fetched key. + + @retval EFI_NOT_READY If serial buffer is empty. + @retval EFI_DEVICE_ERROR If reading serial buffer encounter error. + @retval EFI_SUCCESS If reading serial buffer successfully, put + the fetched key to the parameter output. + +**/ +EFI_STATUS +GetOneKeyFromSerial ( + EFI_SERIAL_IO_PROTOCOL *SerialIo, + UINT8 *Output + ) +{ + EFI_STATUS Status; + UINTN Size; + + Size = 1; + *Output = 0; + + // + // Read one key from serial I/O device. + // + Status = SerialIo->Read (SerialIo, &Size, Output); + + if (EFI_ERROR (Status)) { + + if (Status == EFI_TIMEOUT) { + return EFI_NOT_READY; + } + + return EFI_DEVICE_ERROR; + + } + + if (*Output == 0) { + return EFI_NOT_READY; + } + + return EFI_SUCCESS; +} + +/** + Insert one byte raw data into the Raw Data FIFO. + + @param TerminalDevice Terminal driver private structure. + @param Input The key will be input. + + @retval TRUE If insert successfully. + @retval FLASE If Raw Data buffer is full before key insertion, + and the key is lost. + +**/ +BOOLEAN +RawFiFoInsertOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT8 Input + ) +{ + 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; +} + +/** + Remove one pre-fetched key out of the Raw Data FIFO. + + @param TerminalDevice Terminal driver private structure. + @param Output The key will be removed. + + @retval TRUE If insert successfully. + @retval FLASE If Raw Data FIFO buffer is empty before remove operation. + +**/ +BOOLEAN +RawFiFoRemoveOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT8 *Output + ) +{ + 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; +} + +/** + Clarify whether Raw Data FIFO buffer is empty. + + @param TerminalDevice Terminal driver private structure + + @retval TRUE If Raw Data FIFO buffer is empty. + @retval FLASE If Raw Data FIFO buffer is not empty. + +**/ +BOOLEAN +IsRawFiFoEmpty ( + TERMINAL_DEV *TerminalDevice + ) +{ + if (TerminalDevice->RawFiFo->Head == TerminalDevice->RawFiFo->Tail) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Clarify whether Raw Data FIFO buffer is full. + + @param TerminalDevice Terminal driver private structure + + @retval TRUE If Raw Data FIFO buffer is full. + @retval FLASE If Raw Data FIFO buffer is not full. + +**/ +BOOLEAN +IsRawFiFoFull ( + TERMINAL_DEV *TerminalDevice + ) +{ + 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; +} + +/** + Insert one pre-fetched key into the FIFO buffer. + + @param TerminalDevice Terminal driver private structure. + @param Key The key will be input. + + @retval TRUE If insert successfully. + @retval FLASE If FIFO buffer is full before key insertion, + and the key is lost. + +**/ +BOOLEAN +EfiKeyFiFoInsertOneKey ( + TERMINAL_DEV *TerminalDevice, + EFI_INPUT_KEY *Key + ) +{ + UINT8 Tail; + LIST_ENTRY *Link; + LIST_ENTRY *NotifyList; + TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + EFI_KEY_DATA KeyData; + + Tail = TerminalDevice->EfiKeyFiFo->Tail; + + CopyMem (&KeyData.Key, Key, sizeof (EFI_INPUT_KEY)); + KeyData.KeyState.KeyShiftState = 0; + KeyData.KeyState.KeyToggleState = 0; + + // + // Invoke notification functions if exist + // + NotifyList = &TerminalDevice->NotifyList; + for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) { + CurrentNotify = CR ( + Link, + TERMINAL_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE + ); + if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { + CurrentNotify->KeyNotificationFn (&KeyData); + } + } + if (IsEfiKeyFiFoFull (TerminalDevice)) { + // + // Efi Key FIFO is full + // + return FALSE; + } + + CopyMem (&TerminalDevice->EfiKeyFiFo->Data[Tail], Key, sizeof (EFI_INPUT_KEY)); + + TerminalDevice->EfiKeyFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1)); + + return TRUE; +} + +/** + Remove one pre-fetched key out of the FIFO buffer. + + @param TerminalDevice Terminal driver private structure. + @param Output The key will be removed. + + @retval TRUE If insert successfully. + @retval FLASE If FIFO buffer is empty before remove operation. + +**/ +BOOLEAN +EfiKeyFiFoRemoveOneKey ( + TERMINAL_DEV *TerminalDevice, + EFI_INPUT_KEY *Output + ) +{ + UINT8 Head; + + Head = TerminalDevice->EfiKeyFiFo->Head; + ASSERT (Head < FIFO_MAX_NUMBER + 1); + + 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; +} + +/** + Clarify whether FIFO buffer is empty. + + @param TerminalDevice Terminal driver private structure + + @retval TRUE If FIFO buffer is empty. + @retval FLASE If FIFO buffer is not empty. + +**/ +BOOLEAN +IsEfiKeyFiFoEmpty ( + TERMINAL_DEV *TerminalDevice + ) +{ + if (TerminalDevice->EfiKeyFiFo->Head == TerminalDevice->EfiKeyFiFo->Tail) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Clarify whether FIFO buffer is full. + + @param TerminalDevice Terminal driver private structure + + @retval TRUE If FIFO buffer is full. + @retval FLASE If FIFO buffer is not full. + +**/ +BOOLEAN +IsEfiKeyFiFoFull ( + TERMINAL_DEV *TerminalDevice + ) +{ + UINT8 Tail; + UINT8 Head; + + Tail = TerminalDevice->EfiKeyFiFo->Tail; + Head = TerminalDevice->EfiKeyFiFo->Head; + + if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) { + + return TRUE; + } + + return FALSE; +} + +/** + Insert one pre-fetched key into the Unicode FIFO buffer. + + @param TerminalDevice Terminal driver private structure. + @param Input The key will be input. + + @retval TRUE If insert successfully. + @retval FLASE If Unicode FIFO buffer is full before key insertion, + and the key is lost. + +**/ +BOOLEAN +UnicodeFiFoInsertOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT16 Input + ) +{ + UINT8 Tail; + + Tail = TerminalDevice->UnicodeFiFo->Tail; + ASSERT (Tail < FIFO_MAX_NUMBER + 1); + + + 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; +} + +/** + Remove one pre-fetched key out of the Unicode FIFO buffer. + + @param TerminalDevice Terminal driver private structure. + @param Output The key will be removed. + + @retval TRUE If insert successfully. + @retval FLASE If Unicode FIFO buffer is empty before remove operation. + +**/ +BOOLEAN +UnicodeFiFoRemoveOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT16 *Output + ) +{ + UINT8 Head; + + Head = TerminalDevice->UnicodeFiFo->Head; + ASSERT (Head < FIFO_MAX_NUMBER + 1); + + 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; +} + +/** + Clarify whether Unicode FIFO buffer is empty. + + @param TerminalDevice Terminal driver private structure + + @retval TRUE If Unicode FIFO buffer is empty. + @retval FLASE If Unicode FIFO buffer is not empty. + +**/ +BOOLEAN +IsUnicodeFiFoEmpty ( + TERMINAL_DEV *TerminalDevice + ) +{ + if (TerminalDevice->UnicodeFiFo->Head == TerminalDevice->UnicodeFiFo->Tail) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Clarify whether Unicode FIFO buffer is full. + + @param TerminalDevice Terminal driver private structure + + @retval TRUE If Unicode FIFO buffer is full. + @retval FLASE If Unicode FIFO buffer is not full. + +**/ +BOOLEAN +IsUnicodeFiFoFull ( + TERMINAL_DEV *TerminalDevice + ) +{ + UINT8 Tail; + UINT8 Head; + + Tail = TerminalDevice->UnicodeFiFo->Tail; + Head = TerminalDevice->UnicodeFiFo->Head; + + if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) { + + return TRUE; + } + + return FALSE; +} + +/** + Count Unicode FIFO buffer. + + @param TerminalDevice Terminal driver private structure + + @return The count in bytes of Unicode FIFO. + +**/ +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); + } +} + +/** + Update the Unicode characters from a terminal input device into EFI Keys FIFO. + + @param TerminalDevice The terminal device to use to translate raw input into EFI Keys + +**/ +VOID +UnicodeToEfiKeyFlushState ( + IN TERMINAL_DEV *TerminalDevice + ) +{ + EFI_INPUT_KEY Key; + UINT32 InputState; + + InputState = TerminalDevice->InputState; + + if( IsEfiKeyFiFoFull(TerminalDevice) ) return; + + if ((InputState & INPUT_STATE_ESC) != 0) { + Key.ScanCode = SCAN_ESC; + Key.UnicodeChar = 0; + EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); + } + + if ((InputState & INPUT_STATE_CSI) != 0) { + Key.ScanCode = SCAN_NULL; + Key.UnicodeChar = CSI; + EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); + } + + if ((InputState & INPUT_STATE_LEFTOPENBRACKET) != 0) { + Key.ScanCode = SCAN_NULL; + Key.UnicodeChar = LEFTOPENBRACKET; + EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); + } + + if ((InputState & INPUT_STATE_O) != 0) { + Key.ScanCode = SCAN_NULL; + Key.UnicodeChar = 'O'; + EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); + } + + if ((InputState & INPUT_STATE_2) != 0) { + Key.ScanCode = SCAN_NULL; + Key.UnicodeChar = '2'; + EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); + } + + // + // Cancel the timer. + // + gBS->SetTimer ( + TerminalDevice->TwoSecondTimeOut, + TimerCancel, + 0 + ); + + TerminalDevice->InputState = INPUT_STATE_DEFAULT; +} + + +/** + 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 corresponding 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. + + Note: current implementation support terminal types include: PC ANSI, VT100+/VTUTF8, VT100. + The table below is not same with UEFI Spec 2.3 Appendix B Table 201(not support ANSI X3.64 / + DEC VT200-500 and extra support PC ANSI, VT100)since UEFI Table 201 is just an example. + + Symbols used in table below + =========================== + ESC = 0x1B + CSI = 0x9B + DEL = 0x7f + ^ = CTRL + + +=========+======+===========+==========+==========+ + | | EFI | UEFI 2.0 | | | + | | 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 | + | F11 | 0x15 | | ESC ! | | + | F12 | 0x16 | | ESC @ | | + +=========+======+===========+==========+==========+ + + Special Mappings + ================ + ESC R ESC r ESC R = Reset System + + @param TerminalDevice The terminal device to use to translate raw input into EFI Keys + +**/ +VOID +UnicodeToEfiKey ( + IN TERMINAL_DEV *TerminalDevice + ) +{ + 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) && !IsEfiKeyFiFoFull(TerminalDevice) ) { + + if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) { + // + // Check to see if the 2 seconds 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 '!': + Key.ScanCode = SCAN_F11; + break; + case '@': + Key.ScanCode = SCAN_F12; + 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 (UnicodeChar == CSI) { + TerminalDevice->InputState = INPUT_STATE_CSI; + } + + 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/Vtutf8.c b/MdeModulePkg/Universal/Console/TerminalDxe/Vtutf8.c index 26fc13147a..1ad2f9c6b8 100644 --- a/MdeModulePkg/Universal/Console/TerminalDxe/Vtutf8.c +++ b/MdeModulePkg/Universal/Console/TerminalDxe/Vtutf8.c @@ -1,328 +1,328 @@ -/** @file - Implementation of translation upon VT-UTF8. - -Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "Terminal.h" - -/** - Translate all VT-UTF8 characters in the Raw FIFI into unicode characters, - and insert them into Unicode FIFO. - - @param TerminalDevice The terminal device. - -**/ -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); - } -} - -/** - Get one valid VT-UTF8 characters set from Raw Data FIFO. - - @param Utf8Device The terminal device. - @param Utf8Char Returned valid VT-UTF8 characters set. - @param ValidBytes The count of returned VT-VTF8 characters. - If ValidBytes is zero, no valid VT-UTF8 returned. - -**/ -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: - // - // two-byte utf8 char go on - // - if ((Temp & 0xc0) == 0x80) { - - Utf8Char->Utf8_2[0] = Temp; - - FetchFlag = FALSE; - - } else { - - *ValidBytes = 0; - } - break; - - case 3: - // - // three-byte utf8 char go on - // - if ((Temp & 0xc0) == 0x80) { - if (Index == 1) { - Utf8Char->Utf8_3[1] = Temp; - Index++; - } else { - Utf8Char->Utf8_3[0] = Temp; - FetchFlag = FALSE; - } - } else { - // - // reset *ValidBytes and Index to zero, let valid utf8 char search restart - // - *ValidBytes = 0; - Index = 0; - } - break; - - default: - break; - } - - if (!FetchFlag) { - break; - } - } - - return ; -} - -/** - Translate VT-UTF8 characters into one Unicode character. - - UTF8 Encoding Table - Bits per Character | Unicode Character Range | Unicode Binary Encoding | UTF8 Binary Encoding - 0-7 | 0x0000 - 0x007F | 00000000 0xxxxxxx | 0xxxxxxx - 8-11 | 0x0080 - 0x07FF | 00000xxx xxxxxxxx | 110xxxxx 10xxxxxx - 12-16 | 0x0800 - 0xFFFF | xxxxxxxx xxxxxxxx | 1110xxxx 10xxxxxx 10xxxxxx - - - @param Utf8Char VT-UTF8 character set needs translating. - @param ValidBytes The count of valid VT-UTF8 characters. - @param UnicodeChar Returned unicode character. - -**/ -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 ; -} - -/** - Translate one Unicode character into VT-UTF8 characters. - - UTF8 Encoding Table - Bits per Character | Unicode Character Range | Unicode Binary Encoding | UTF8 Binary Encoding - 0-7 | 0x0000 - 0x007F | 00000000 0xxxxxxx | 0xxxxxxx - 8-11 | 0x0080 - 0x07FF | 00000xxx xxxxxxxx | 110xxxxx 10xxxxxx - 12-16 | 0x0800 - 0xFFFF | xxxxxxxx xxxxxxxx | 1110xxxx 10xxxxxx 10xxxxxx - - - @param Unicode Unicode character need translating. - @param Utf8Char Return VT-UTF8 character set. - @param ValidBytes The count of valid VT-UTF8 characters. If - ValidBytes is zero, no valid VT-UTF8 returned. - -**/ -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; - } -} - - -/** - Check if input string is valid VT-UTF8 string. - - @param TerminalDevice The terminal device. - @param WString The input string. - - @retval EFI_SUCCESS If all input characters are valid. - -**/ -EFI_STATUS -VTUTF8TestString ( - IN TERMINAL_DEV *TerminalDevice, - IN CHAR16 *WString - ) -{ - // - // to utf8, all kind of characters are supported. - // - return EFI_SUCCESS; -} +/** @file + Implementation of translation upon VT-UTF8. + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Terminal.h" + +/** + Translate all VT-UTF8 characters in the Raw FIFI into unicode characters, + and insert them into Unicode FIFO. + + @param TerminalDevice The terminal device. + +**/ +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) && !IsUnicodeFiFoFull(TerminalDevice) ) { + + GetOneValidUtf8Char (TerminalDevice, &Utf8Char, &ValidBytes); + + if (ValidBytes < 1 || ValidBytes > 3) { + continue; + } + + Utf8ToUnicode (Utf8Char, ValidBytes, (CHAR16 *) &UnicodeChar); + + UnicodeFiFoInsertOneKey (TerminalDevice, UnicodeChar); + } +} + +/** + Get one valid VT-UTF8 characters set from Raw Data FIFO. + + @param Utf8Device The terminal device. + @param Utf8Char Returned valid VT-UTF8 characters set. + @param ValidBytes The count of returned VT-VTF8 characters. + If ValidBytes is zero, no valid VT-UTF8 returned. + +**/ +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: + // + // two-byte utf8 char go on + // + if ((Temp & 0xc0) == 0x80) { + + Utf8Char->Utf8_2[0] = Temp; + + FetchFlag = FALSE; + + } else { + + *ValidBytes = 0; + } + break; + + case 3: + // + // three-byte utf8 char go on + // + if ((Temp & 0xc0) == 0x80) { + if (Index == 1) { + Utf8Char->Utf8_3[1] = Temp; + Index++; + } else { + Utf8Char->Utf8_3[0] = Temp; + FetchFlag = FALSE; + } + } else { + // + // reset *ValidBytes and Index to zero, let valid utf8 char search restart + // + *ValidBytes = 0; + Index = 0; + } + break; + + default: + break; + } + + if (!FetchFlag) { + break; + } + } + + return ; +} + +/** + Translate VT-UTF8 characters into one Unicode character. + + UTF8 Encoding Table + Bits per Character | Unicode Character Range | Unicode Binary Encoding | UTF8 Binary Encoding + 0-7 | 0x0000 - 0x007F | 00000000 0xxxxxxx | 0xxxxxxx + 8-11 | 0x0080 - 0x07FF | 00000xxx xxxxxxxx | 110xxxxx 10xxxxxx + 12-16 | 0x0800 - 0xFFFF | xxxxxxxx xxxxxxxx | 1110xxxx 10xxxxxx 10xxxxxx + + + @param Utf8Char VT-UTF8 character set needs translating. + @param ValidBytes The count of valid VT-UTF8 characters. + @param UnicodeChar Returned unicode character. + +**/ +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 ; +} + +/** + Translate one Unicode character into VT-UTF8 characters. + + UTF8 Encoding Table + Bits per Character | Unicode Character Range | Unicode Binary Encoding | UTF8 Binary Encoding + 0-7 | 0x0000 - 0x007F | 00000000 0xxxxxxx | 0xxxxxxx + 8-11 | 0x0080 - 0x07FF | 00000xxx xxxxxxxx | 110xxxxx 10xxxxxx + 12-16 | 0x0800 - 0xFFFF | xxxxxxxx xxxxxxxx | 1110xxxx 10xxxxxx 10xxxxxx + + + @param Unicode Unicode character need translating. + @param Utf8Char Return VT-UTF8 character set. + @param ValidBytes The count of valid VT-UTF8 characters. If + ValidBytes is zero, no valid VT-UTF8 returned. + +**/ +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; + } +} + + +/** + Check if input string is valid VT-UTF8 string. + + @param TerminalDevice The terminal device. + @param WString The input string. + + @retval EFI_SUCCESS If all input characters are valid. + +**/ +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