X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FUniversal%2FConsole%2FTerminalDxe%2FTerminalConIn.c;h=4ede41677493da9c72af5a37ac8cb175cb3b4567;hp=4b3eb370237499f882ca953c2f7dfbbddb3d8af3;hb=9d510e61fceee7b92955ef9a3c20343752d8ce3f;hpb=66aa04e4e3a0b84369cbb483a78c4113b619663a diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c index 4b3eb37023..4ede416774 100644 --- a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c +++ b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c @@ -1,120 +1,69 @@ -/**@file +/** @file Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol. - -Copyright (c) 2006 - 2007 Intel Corporation.
-All rights reserved. This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +(C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (C) 2016 Silicon Graphics, Inc. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "Terminal.h" -STATIC +/** + 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 ) -/*++ - - Routine Description: - Reads the next keystroke from the input device. The WaitForKey Event can - be used to test for existance of a keystroke via WaitForEvent () call. - - Arguments: - TerminalDevice - Terminal driver private structure - KeyData - A pointer to a buffer that is filled in with the keystroke - state data for the key that was pressed. - - Returns: - EFI_SUCCESS - The keystroke information was returned. - EFI_NOT_READY - There was no keystroke data availiable. - EFI_DEVICE_ERROR - The keystroke information was not returned due to - hardware errors. - EFI_INVALID_PARAMETER - KeyData is NULL. - ---*/ { - EFI_STATUS Status; - LIST_ENTRY *Link; - TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; - if (KeyData == NULL) { return EFI_INVALID_PARAMETER; - } - - // - // Initialize *Key to nonsense value. - // - KeyData->Key.ScanCode = SCAN_NULL; - KeyData->Key.UnicodeChar = 0; - - Status = TerminalConInCheckForKey (&TerminalDevice->SimpleInput); - if (EFI_ERROR (Status)) { - return EFI_NOT_READY; - } - - if (!EfiKeyFiFoRemoveOneKey (TerminalDevice, &KeyData->Key)) { - return EFI_NOT_READY; } KeyData->KeyState.KeyShiftState = 0; KeyData->KeyState.KeyToggleState = 0; - // - // Invoke notification functions if exist - // - for (Link = TerminalDevice->NotifyList.ForwardLink; Link != &TerminalDevice->NotifyList; Link = Link->ForwardLink) { - CurrentNotify = CR ( - Link, - TERMINAL_CONSOLE_IN_EX_NOTIFY, - NotifyEntry, - TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE - ); - if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { - CurrentNotify->KeyNotificationFn (KeyData); - } + if (!EfiKeyFiFoRemoveOneKey (TerminalDevice, &KeyData->Key)) { + return EFI_NOT_READY; } 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 ) -/*++ - Routine Description: - - Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset(). - This driver only perform dependent serial device reset regardless of - the value of ExtendeVerification - - Arguments: - - This - Indicates the calling context. - - ExtendedVerification - Skip by this driver. - - Returns: - - EFI_SUCCESS - The reset operation succeeds. - - EFI_DEVICE_ERROR - The dependent serial port reset fails. - ---*/ { EFI_STATUS Status; TERMINAL_DEV *TerminalDevice; @@ -126,23 +75,24 @@ TerminalConInReset ( // REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_PROGRESS_CODE, - PcdGet32 (PcdStatusCodeValueRemoteConsoleReset), + (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_RESET), TerminalDevice->DevicePath ); Status = TerminalDevice->SerialIo->Reset (TerminalDevice->SerialIo); // - // clear all the internal buffer for keys + // Make all the internal buffer empty for keys // - InitializeRawFiFo (TerminalDevice); - InitializeUnicodeFiFo (TerminalDevice); - InitializeEfiKeyFiFo (TerminalDevice); + TerminalDevice->RawFiFo->Head = TerminalDevice->RawFiFo->Tail; + TerminalDevice->UnicodeFiFo->Head = TerminalDevice->UnicodeFiFo->Tail; + TerminalDevice->EfiKeyFiFo->Head = TerminalDevice->EfiKeyFiFo->Tail; + TerminalDevice->EfiKeyFiFoForNotify->Head = TerminalDevice->EfiKeyFiFoForNotify->Tail; if (EFI_ERROR (Status)) { REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_ERROR_CODE | EFI_ERROR_MINOR, - PcdGet32 (PcdStatusCodeValueRemoteConsoleError), + (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR), TerminalDevice->DevicePath ); } @@ -150,36 +100,25 @@ TerminalConInReset ( 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 ) -/*++ - Routine Description: - - Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke(). - - Arguments: - - This - Indicates the calling context. - - Key - A pointer to a buffer that is filled in with the keystroke - information for the key that was sent from terminal. - - Returns: - - EFI_SUCCESS - The keystroke information is returned successfully. - - EFI_NOT_READY - There is no keystroke data available. - - EFI_DEVICE_ERROR - The dependent serial device encounters error. - ---*/ { TERMINAL_DEV *TerminalDevice; EFI_STATUS Status; @@ -201,97 +140,79 @@ TerminalConInReadKeyStroke ( } +/** + 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 FALSE Match failed. + +**/ BOOLEAN IsKeyRegistered ( IN EFI_KEY_DATA *RegsiteredData, IN EFI_KEY_DATA *InputData ) -/*++ - -Routine Description: - -Arguments: - - RegsiteredData - A pointer to a buffer that is filled in with the keystroke - state data for the key that was registered. - InputData - A pointer to a buffer that is filled in with the keystroke - state data for the key that was pressed. - -Returns: - TRUE - Key be pressed matches a registered key. - FLASE - Match failed. - ---*/ { ASSERT (RegsiteredData != NULL && InputData != NULL); - + if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) || (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) { - return FALSE; - } - + 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 ) -/*++ - Routine Description: - - Event notification function for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event - Signal the event if there is key available - - Arguments: - - Event - Indicates the event that invoke this function. - - Context - Indicates the calling context. - - Returns: - - N/A - ---*/ { - TERMINAL_DEV *TerminalDevice; - - TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (Context); - - TerminalConInWaitForKey (Event, &TerminalDevice->SimpleInput); - + 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 ) -/*++ - - Routine Description: - Reset the input device and optionaly run diagnostics - - Arguments: - This - Protocol instance pointer. - ExtendedVerification - Driver may perform diagnostics on reset. - - Returns: - EFI_SUCCESS - The device was reset. - EFI_DEVICE_ERROR - The device is not functioning properly and could - not be reset. - ---*/ { EFI_STATUS Status; TERMINAL_DEV *TerminalDevice; @@ -304,40 +225,38 @@ TerminalConInResetEx ( } 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 ) -/*++ - - Routine Description: - Reads the next keystroke from the input device. The WaitForKey Event can - be used to test for existance of a keystroke via WaitForEvent () call. - - Arguments: - This - Protocol instance pointer. - KeyData - A pointer to a buffer that is filled in with the keystroke - state data for the key that was pressed. - - Returns: - EFI_SUCCESS - The keystroke information was returned. - EFI_NOT_READY - There was no keystroke data availiable. - EFI_DEVICE_ERROR - The keystroke information was not returned due to - hardware errors. - EFI_INVALID_PARAMETER - KeyData is NULL. - ---*/ { TERMINAL_DEV *TerminalDevice; if (KeyData == NULL) { return EFI_INVALID_PARAMETER; - } + } TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This); @@ -345,71 +264,77 @@ TerminalConInReadKeyStrokeEx ( } + +/** + 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 ) -/*++ - - Routine Description: - Set certain state for the input device. - - Arguments: - This - Protocol instance pointer. - KeyToggleState - A pointer to the EFI_KEY_TOGGLE_STATE to set the - state for the input device. - - Returns: - EFI_SUCCESS - The device state was set successfully. - EFI_DEVICE_ERROR - The device is not functioning correctly and could - not have the setting adjusted. - EFI_UNSUPPORTED - The device does not have the ability to set its state. - EFI_INVALID_PARAMETER - KeyToggleState is NULL. - ---*/ { if (KeyToggleState == NULL) { return EFI_INVALID_PARAMETER; } + if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) { + return EFI_UNSUPPORTED; + } + 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 for the key that was + pressed. If KeyData.Key, KeyData.KeyState.KeyToggleState + and KeyData.KeyState.KeyShiftState are 0, then any incomplete + keystroke will trigger a notification of the KeyNotificationFunction. + @param KeyNotificationFunction Points to the function to be called when the key + sequence is typed specified by KeyData. This notification function + should be called at <=TPL_CALLBACK. + @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 + OUT VOID **NotifyHandle ) -/*++ - - Routine Description: - Register a notification function for a particular keystroke for the input device. - - Arguments: - This - Protocol instance pointer. - KeyData - A pointer to a buffer that is filled in with the keystroke - information data for the key that was pressed. - KeyNotificationFunction - Points to the function to be called when the key - sequence is typed specified by KeyData. - NotifyHandle - Points to the unique handle assigned to the registered notification. - - Returns: - EFI_SUCCESS - The notification function was registered successfully. - EFI_OUT_OF_RESOURCES - Unable to allocate resources for necesssary data structures. - EFI_INVALID_PARAMETER - KeyData or NotifyHandle is NULL. - ---*/ { - EFI_STATUS Status; TERMINAL_DEV *TerminalDevice; TERMINAL_CONSOLE_IN_EX_NOTIFY *NewNotify; LIST_ENTRY *Link; - TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + LIST_ENTRY *NotifyList; + TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) { return EFI_INVALID_PARAMETER; @@ -420,16 +345,17 @@ TerminalConInRegisterKeyNotify ( // // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered. // - for (Link = TerminalDevice->NotifyList.ForwardLink; Link != &TerminalDevice->NotifyList; Link = Link->ForwardLink) { + NotifyList = &TerminalDevice->NotifyList; + for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) { CurrentNotify = CR ( - Link, - TERMINAL_CONSOLE_IN_EX_NOTIFY, - NotifyEntry, + Link, + TERMINAL_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE ); - if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { + if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { - *NotifyHandle = CurrentNotify->NotifyHandle; + *NotifyHandle = CurrentNotify; return EFI_SUCCESS; } } @@ -437,124 +363,101 @@ TerminalConInRegisterKeyNotify ( // // 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->Signature = TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE; NewNotify->KeyNotificationFn = KeyNotificationFunction; - CopyMem (&NewNotify->KeyData, KeyData, sizeof (KeyData)); + CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA)); InsertTailList (&TerminalDevice->NotifyList, &NewNotify->NotifyEntry); - // - // Use gSimpleTextInExNotifyGuid to get a valid EFI_HANDLE - // - Status = gBS->InstallMultipleProtocolInterfaces ( - &NewNotify->NotifyHandle, - &gSimpleTextInExNotifyGuid, - NULL, - NULL - ); - ASSERT_EFI_ERROR (Status); - *NotifyHandle = NewNotify->NotifyHandle; + + *NotifyHandle = NewNotify; return EFI_SUCCESS; } + +/** + Remove a registered notification function from a particular keystroke. + + @param This Protocol instance pointer. + @param NotificationHandle The handle of the notification function being + unregistered. + + @retval EFI_SUCCESS The notification function was unregistered + successfully. + @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid. + +**/ EFI_STATUS EFIAPI TerminalConInUnregisterKeyNotify ( IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - IN EFI_HANDLE NotificationHandle + IN VOID *NotificationHandle ) -/*++ - - Routine Description: - Remove a registered notification function from a particular keystroke. - - Arguments: - This - Protocol instance pointer. - NotificationHandle - The handle of the notification function being unregistered. - - Returns: - EFI_SUCCESS - The notification function was unregistered successfully. - EFI_INVALID_PARAMETER - The NotificationHandle is invalid. - EFI_NOT_FOUND - Can not find the matching entry in database. - ---*/ { - EFI_STATUS Status; TERMINAL_DEV *TerminalDevice; LIST_ENTRY *Link; TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + LIST_ENTRY *NotifyList; if (NotificationHandle == NULL) { return EFI_INVALID_PARAMETER; - } - - Status = gBS->OpenProtocol ( - NotificationHandle, - &gSimpleTextInExNotifyGuid, - NULL, - NULL, - NULL, - EFI_OPEN_PROTOCOL_TEST_PROTOCOL - ); - if (EFI_ERROR (Status)) { - return EFI_INVALID_PARAMETER; } TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This); - for (Link = TerminalDevice->NotifyList.ForwardLink; Link != &TerminalDevice->NotifyList; Link = Link->ForwardLink) { + NotifyList = &TerminalDevice->NotifyList; + for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) { CurrentNotify = CR ( - Link, - TERMINAL_CONSOLE_IN_EX_NOTIFY, - NotifyEntry, + Link, + TERMINAL_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE ); - if (CurrentNotify->NotifyHandle == NotificationHandle) { + if (CurrentNotify == NotificationHandle) { // // Remove the notification function from NotifyList and free resources // - RemoveEntryList (&CurrentNotify->NotifyEntry); - Status = gBS->UninstallMultipleProtocolInterfaces ( - CurrentNotify->NotifyHandle, - &gSimpleTextInExNotifyGuid, - NULL, - NULL - ); - ASSERT_EFI_ERROR (Status); - gBS->FreePool (CurrentNotify); + RemoveEntryList (&CurrentNotify->NotifyEntry); + + gBS->FreePool (CurrentNotify); return EFI_SUCCESS; } } - - return EFI_NOT_FOUND; + + // + // 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 ) -/*++ - Step1: Turn raw data into Unicode (according to different encode). - Step2: Translate Unicode into key information. - (according to different terminal standard). ---*/ { switch (TerminalDevice->TerminalType) { - case PcAnsiType: - case VT100Type: - case VT100PlusType: + case TerminalTypePcAnsi: + case TerminalTypeVt100: + case TerminalTypeVt100Plus: + case TerminalTypeTtyTerm: AnsiRawDataToUnicode (TerminalDevice); UnicodeToEfiKey (TerminalDevice); break; - case VTUTF8Type: + case TerminalTypeVtUtf8: // // Process all the raw data in the RawFIFO, // put the processed key into UnicodeFIFO. @@ -571,66 +474,43 @@ TranslateRawDataToEfiKey ( } } +/** + 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 ) -/*++ - Routine Description: - - Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event - Signal the event if there is key available - - Arguments: - - Event - Indicates the event that invoke this function. - - Context - Indicates the calling context. - - Returns: - - N/A - ---*/ { // // Someone is waiting on the keystroke event, if there's // a key pending, signal the event // - // Context is the pointer to EFI_SIMPLE_TEXT_INPUT_PROTOCOL - // - if (!EFI_ERROR (TerminalConInCheckForKey (Context))) { + if (!IsEfiKeyFiFoEmpty ((TERMINAL_DEV *) Context)) { gBS->SignalEvent (Event); } } -EFI_STATUS -TerminalConInCheckForKey ( - IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This +/** + 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 ) -/*++ - Routine Description: - - Check for a pending key in the Efi Key FIFO or Serial device buffer. - - Arguments: - - This - Indicates the calling context. - - Returns: - - EFI_SUCCESS - There is key pending. - - EFI_NOT_READY - There is no key pending. - - EFI_DEVICE_ERROR - ---*/ { EFI_STATUS Status; TERMINAL_DEV *TerminalDevice; @@ -640,11 +520,11 @@ TerminalConInCheckForKey ( EFI_SERIAL_IO_PROTOCOL *SerialIo; UINTN SerialInTimeOut; - TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This); + TerminalDevice = (TERMINAL_DEV *) Context; SerialIo = TerminalDevice->SerialIo; if (SerialIo == NULL) { - return EFI_DEVICE_ERROR; + return ; } // // if current timeout value for serial device is not identical with @@ -656,6 +536,9 @@ TerminalConInCheckForKey ( 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; } @@ -676,82 +559,123 @@ TerminalConInCheckForKey ( } } // - // check whether serial buffer is empty + // Check whether serial buffer is empty. + // Skip the key transfer loop only if the SerialIo protocol instance + // successfully reports EFI_SERIAL_INPUT_BUFFER_EMPTY. // Status = SerialIo->GetControl (SerialIo, &Control); - - if (Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) { - // - // Translate all the raw data in RawFIFO into EFI Key, - // according to different terminal type supported. + if (EFI_ERROR (Status) || ((Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) == 0)) { // - TranslateRawDataToEfiKey (TerminalDevice); - - // - // if there is pre-fetched Efi Key in EfiKeyFIFO buffer, - // return directly. + // Fetch all the keys in the serial buffer, + // and insert the byte stream into RawFIFO. // - if (!IsEfiKeyFiFoEmpty (TerminalDevice)) { - return EFI_SUCCESS; - } else { - return EFI_NOT_READY; - } - } - // - // Fetch all the keys in the serial buffer, - // and insert the byte stream into RawFIFO. - // - do { + while (!IsRawFiFoFull (TerminalDevice)) { - Status = GetOneKeyFromSerial (TerminalDevice->SerialIo, &Input); + 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, - PcdGet32 (PcdStatusCodeValueRemoteConsoleInputError), - TerminalDevice->DevicePath - ); + 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; } - break; - } - RawFiFoInsertOneKey (TerminalDevice, Input); - } while (TRUE); + RawFiFoInsertOneKey (TerminalDevice, Input); + } + } // // Translate all the raw data in RawFIFO into EFI Key, // according to different terminal type supported. // TranslateRawDataToEfiKey (TerminalDevice); +} - if (IsEfiKeyFiFoEmpty (TerminalDevice)) { - return EFI_NOT_READY; - } +/** + Process key notify. - return EFI_SUCCESS; + @param Event Indicates the event that invoke this function. + @param Context Indicates the calling context. +**/ +VOID +EFIAPI +KeyNotifyProcessHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + BOOLEAN HasKey; + TERMINAL_DEV *TerminalDevice; + EFI_INPUT_KEY Key; + EFI_KEY_DATA KeyData; + LIST_ENTRY *Link; + LIST_ENTRY *NotifyList; + TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + EFI_TPL OldTpl; + + TerminalDevice = (TERMINAL_DEV *) Context; + + // + // Invoke notification functions. + // + NotifyList = &TerminalDevice->NotifyList; + while (TRUE) { + // + // Enter critical section + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + HasKey = EfiKeyFiFoForNotifyRemoveOneKey (TerminalDevice->EfiKeyFiFoForNotify, &Key); + CopyMem (&KeyData.Key, &Key, sizeof (EFI_INPUT_KEY)); + KeyData.KeyState.KeyShiftState = 0; + KeyData.KeyState.KeyToggleState = 0; + // + // Leave critical section + // + gBS->RestoreTPL (OldTpl); + if (!HasKey) { + break; + } + 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); + } + } + } } +/** + 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 *Input + UINT8 *Output ) -/*++ - Get one key out of serial buffer. - If serial buffer is empty, return EFI_NOT_READY; - if reading serial buffer encounter error, returns EFI_DEVICE_ERROR; - if reading serial buffer successfully, put the fetched key to - the parameter "Input", and return EFI_SUCCESS. ---*/ { EFI_STATUS Status; UINTN Size; Size = 1; - *Input = 0; + *Output = 0; - Status = SerialIo->Read (SerialIo, &Size, Input); + // + // Read one key from serial I/O device. + // + Status = SerialIo->Read (SerialIo, &Size, Output); if (EFI_ERROR (Status)) { @@ -763,27 +687,33 @@ GetOneKeyFromSerial ( } - if (*Input == 0) { + 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 FALSE If Raw Data buffer is full before key insertion, + and the key is lost. + +**/ BOOLEAN RawFiFoInsertOneKey ( TERMINAL_DEV *TerminalDevice, UINT8 Input ) -/*++ - Insert one byte raw data into the Raw Data FIFO. - If FIFO is FULL before data insertion, - return FALSE, and the key is lost. ---*/ { UINT8 Tail; - Tail = TerminalDevice->RawFiFo.Tail; + Tail = TerminalDevice->RawFiFo->Tail; if (IsRawFiFoFull (TerminalDevice)) { // @@ -792,27 +722,32 @@ RawFiFoInsertOneKey ( return FALSE; } - TerminalDevice->RawFiFo.Data[Tail] = Input; + TerminalDevice->RawFiFo->Data[Tail] = Input; - TerminalDevice->RawFiFo.Tail = (UINT8) ((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1)); + 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 FALSE If Raw Data FIFO buffer is empty before remove operation. + +**/ BOOLEAN RawFiFoRemoveOneKey ( TERMINAL_DEV *TerminalDevice, UINT8 *Output ) -/*++ - Remove one byte raw data out of the Raw Data FIFO. - If FIFO buffer is empty before remove operation, - return FALSE. ---*/ { UINT8 Head; - Head = TerminalDevice->RawFiFo.Head; + Head = TerminalDevice->RawFiFo->Head; if (IsRawFiFoEmpty (TerminalDevice)) { // @@ -822,41 +757,53 @@ RawFiFoRemoveOneKey ( return FALSE; } - *Output = TerminalDevice->RawFiFo.Data[Head]; + *Output = TerminalDevice->RawFiFo->Data[Head]; - TerminalDevice->RawFiFo.Head = (UINT8) ((Head + 1) % (RAW_FIFO_MAX_NUMBER + 1)); + 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 FALSE If Raw Data FIFO buffer is not empty. + +**/ BOOLEAN IsRawFiFoEmpty ( TERMINAL_DEV *TerminalDevice ) -/*++ - Clarify whether FIFO buffer is empty. ---*/ { - if (TerminalDevice->RawFiFo.Head == TerminalDevice->RawFiFo.Tail) { + 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 FALSE If Raw Data FIFO buffer is not full. + +**/ BOOLEAN IsRawFiFoFull ( TERMINAL_DEV *TerminalDevice ) -/*++ - Clarify whether FIFO buffer is full. ---*/ { UINT8 Tail; UINT8 Head; - Tail = TerminalDevice->RawFiFo.Tail; - Head = TerminalDevice->RawFiFo.Head; + Tail = TerminalDevice->RawFiFo->Tail; + Head = TerminalDevice->RawFiFo->Head; if (((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1)) == Head) { @@ -866,21 +813,177 @@ IsRawFiFoFull ( return FALSE; } +/** + Insert one pre-fetched key into the FIFO buffer. + + @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO. + @param Input The key will be input. + + @retval TRUE If insert successfully. + @retval FALSE If FIFO buffer is full before key insertion, + and the key is lost. + +**/ +BOOLEAN +EfiKeyFiFoForNotifyInsertOneKey ( + EFI_KEY_FIFO *EfiKeyFiFo, + EFI_INPUT_KEY *Input + ) +{ + UINT8 Tail; + + Tail = EfiKeyFiFo->Tail; + + if (IsEfiKeyFiFoForNotifyFull (EfiKeyFiFo)) { + // + // FIFO is full + // + return FALSE; + } + + CopyMem (&EfiKeyFiFo->Data[Tail], Input, sizeof (EFI_INPUT_KEY)); + + EfiKeyFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1)); + + return TRUE; +} + +/** + Remove one pre-fetched key out of the FIFO buffer. + + @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO. + @param Output The key will be removed. + + @retval TRUE If remove successfully. + @retval FALSE If FIFO buffer is empty before remove operation. + +**/ +BOOLEAN +EfiKeyFiFoForNotifyRemoveOneKey ( + EFI_KEY_FIFO *EfiKeyFiFo, + EFI_INPUT_KEY *Output + ) +{ + UINT8 Head; + + Head = EfiKeyFiFo->Head; + ASSERT (Head < FIFO_MAX_NUMBER + 1); + + if (IsEfiKeyFiFoForNotifyEmpty (EfiKeyFiFo)) { + // + // FIFO is empty + // + Output->ScanCode = SCAN_NULL; + Output->UnicodeChar = 0; + return FALSE; + } + + CopyMem (Output, &EfiKeyFiFo->Data[Head], sizeof (EFI_INPUT_KEY)); + + EfiKeyFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1)); + + return TRUE; +} + +/** + Clarify whether FIFO buffer is empty. + + @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO. + + @retval TRUE If FIFO buffer is empty. + @retval FALSE If FIFO buffer is not empty. + +**/ +BOOLEAN +IsEfiKeyFiFoForNotifyEmpty ( + EFI_KEY_FIFO *EfiKeyFiFo + ) +{ + if (EfiKeyFiFo->Head == EfiKeyFiFo->Tail) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Clarify whether FIFO buffer is full. + + @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO. + + @retval TRUE If FIFO buffer is full. + @retval FALSE If FIFO buffer is not full. + +**/ +BOOLEAN +IsEfiKeyFiFoForNotifyFull ( + EFI_KEY_FIFO *EfiKeyFiFo + ) +{ + UINT8 Tail; + UINT8 Head; + + Tail = EfiKeyFiFo->Tail; + Head = EfiKeyFiFo->Head; + + if (((Tail + 1) % (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 FALSE If FIFO buffer is full before key insertion, + and the key is lost. + +**/ BOOLEAN EfiKeyFiFoInsertOneKey ( - TERMINAL_DEV *TerminalDevice, - EFI_INPUT_KEY Key + TERMINAL_DEV *TerminalDevice, + EFI_INPUT_KEY *Key ) -/*++ - Insert one pre-fetched key into the FIFO buffer. - If FIFO buffer is FULL before key insertion, - return FALSE, and the key is lost. ---*/ { - UINT8 Tail; + UINT8 Tail; + LIST_ENTRY *Link; + LIST_ENTRY *NotifyList; + TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + EFI_KEY_DATA KeyData; + + Tail = TerminalDevice->EfiKeyFiFo->Tail; - Tail = TerminalDevice->EfiKeyFiFo.Tail; + CopyMem (&KeyData.Key, Key, sizeof (EFI_INPUT_KEY)); + KeyData.KeyState.KeyShiftState = 0; + KeyData.KeyState.KeyToggleState = 0; + // + // Signal KeyNotify process event if this key pressed matches any key 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)) { + // + // The key notification function needs to run at TPL_CALLBACK + // while current TPL is TPL_NOTIFY. It will be invoked in + // KeyNotifyProcessHandler() which runs at TPL_CALLBACK. + // + EfiKeyFiFoForNotifyInsertOneKey (TerminalDevice->EfiKeyFiFoForNotify, Key); + gBS->SignalEvent (TerminalDevice->KeyNotifyProcessEvent); + break; + } + } if (IsEfiKeyFiFoFull (TerminalDevice)) { // // Efi Key FIFO is full @@ -888,27 +991,33 @@ EfiKeyFiFoInsertOneKey ( return FALSE; } - TerminalDevice->EfiKeyFiFo.Data[Tail] = Key; + CopyMem (&TerminalDevice->EfiKeyFiFo->Data[Tail], Key, sizeof (EFI_INPUT_KEY)); - TerminalDevice->EfiKeyFiFo.Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1)); + 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 FALSE If FIFO buffer is empty before remove operation. + +**/ BOOLEAN EfiKeyFiFoRemoveOneKey ( TERMINAL_DEV *TerminalDevice, EFI_INPUT_KEY *Output ) -/*++ - Remove one pre-fetched key out of the FIFO buffer. - If FIFO buffer is empty before remove operation, - return FALSE. ---*/ { UINT8 Head; - Head = TerminalDevice->EfiKeyFiFo.Head; + Head = TerminalDevice->EfiKeyFiFo->Head; + ASSERT (Head < FIFO_MAX_NUMBER + 1); if (IsEfiKeyFiFoEmpty (TerminalDevice)) { // @@ -919,41 +1028,53 @@ EfiKeyFiFoRemoveOneKey ( return FALSE; } - *Output = TerminalDevice->EfiKeyFiFo.Data[Head]; + CopyMem (Output, &TerminalDevice->EfiKeyFiFo->Data[Head], sizeof (EFI_INPUT_KEY)); - TerminalDevice->EfiKeyFiFo.Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1)); + 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 FALSE If FIFO buffer is not empty. + +**/ BOOLEAN IsEfiKeyFiFoEmpty ( TERMINAL_DEV *TerminalDevice ) -/*++ - Clarify whether FIFO buffer is empty. ---*/ { - if (TerminalDevice->EfiKeyFiFo.Head == TerminalDevice->EfiKeyFiFo.Tail) { + 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 FALSE If FIFO buffer is not full. + +**/ BOOLEAN IsEfiKeyFiFoFull ( TERMINAL_DEV *TerminalDevice ) -/*++ - Clarify whether FIFO buffer is full. ---*/ { UINT8 Tail; UINT8 Head; - Tail = TerminalDevice->EfiKeyFiFo.Tail; - Head = TerminalDevice->EfiKeyFiFo.Head; + Tail = TerminalDevice->EfiKeyFiFo->Tail; + Head = TerminalDevice->EfiKeyFiFo->Head; if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) { @@ -963,20 +1084,28 @@ IsEfiKeyFiFoFull ( 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 FALSE If Unicode FIFO buffer is full before key insertion, + and the key is lost. + +**/ BOOLEAN UnicodeFiFoInsertOneKey ( TERMINAL_DEV *TerminalDevice, UINT16 Input ) -/*++ - Insert one pre-fetched key into the FIFO buffer. - If FIFO buffer is FULL before key insertion, - return FALSE, and the key is lost. ---*/ { UINT8 Tail; - Tail = TerminalDevice->UnicodeFiFo.Tail; + Tail = TerminalDevice->UnicodeFiFo->Tail; + ASSERT (Tail < FIFO_MAX_NUMBER + 1); + if (IsUnicodeFiFoFull (TerminalDevice)) { // @@ -985,71 +1114,78 @@ UnicodeFiFoInsertOneKey ( return FALSE; } - TerminalDevice->UnicodeFiFo.Data[Tail] = Input; + TerminalDevice->UnicodeFiFo->Data[Tail] = Input; - TerminalDevice->UnicodeFiFo.Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1)); + TerminalDevice->UnicodeFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1)); return TRUE; } -BOOLEAN +/** + Remove one pre-fetched key out of the Unicode FIFO buffer. + The caller should guarantee that Unicode FIFO buffer is not empty + by IsUnicodeFiFoEmpty (). + + @param TerminalDevice Terminal driver private structure. + @param Output The key will be removed. + +**/ +VOID UnicodeFiFoRemoveOneKey ( TERMINAL_DEV *TerminalDevice, UINT16 *Output ) -/*++ - Remove one pre-fetched key out of the FIFO buffer. - If FIFO buffer is empty before remove operation, - return FALSE. ---*/ { UINT8 Head; - Head = TerminalDevice->UnicodeFiFo.Head; + 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]; - *Output = TerminalDevice->UnicodeFiFo.Data[Head]; + TerminalDevice->UnicodeFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1)); +} - TerminalDevice->UnicodeFiFo.Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1)); +/** + Clarify whether Unicode FIFO buffer is empty. - return TRUE; -} + @param TerminalDevice Terminal driver private structure + + @retval TRUE If Unicode FIFO buffer is empty. + @retval FALSE If Unicode FIFO buffer is not empty. +**/ BOOLEAN IsUnicodeFiFoEmpty ( TERMINAL_DEV *TerminalDevice ) -/*++ - Clarify whether FIFO buffer is empty. ---*/ { - if (TerminalDevice->UnicodeFiFo.Head == TerminalDevice->UnicodeFiFo.Tail) { + 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 FALSE If Unicode FIFO buffer is not full. + +**/ BOOLEAN IsUnicodeFiFoFull ( TERMINAL_DEV *TerminalDevice ) -/*++ - Clarify whether FIFO buffer is full. ---*/ { UINT8 Tail; UINT8 Head; - Tail = TerminalDevice->UnicodeFiFo.Tail; - Head = TerminalDevice->UnicodeFiFo.Head; + Tail = TerminalDevice->UnicodeFiFo->Tail; + Head = TerminalDevice->UnicodeFiFo->Head; if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) { @@ -1059,62 +1195,60 @@ IsUnicodeFiFoFull ( return FALSE; } -UINT8 -UnicodeFiFoGetKeyCount ( - TERMINAL_DEV *TerminalDevice - ) -{ - UINT8 Tail; - UINT8 Head; - Tail = TerminalDevice->UnicodeFiFo.Tail; - Head = TerminalDevice->UnicodeFiFo.Head; +/** + Update the Unicode characters from a terminal input device into EFI Keys FIFO. - if (Tail >= Head) { - return (UINT8) (Tail - Head); - } else { - return (UINT8) (Tail + FIFO_MAX_NUMBER + 1 - Head); - } -} + @param TerminalDevice The terminal device to use to translate raw input into EFI Keys -STATIC +**/ VOID UnicodeToEfiKeyFlushState ( IN TERMINAL_DEV *TerminalDevice ) { EFI_INPUT_KEY Key; + UINT32 InputState; + + InputState = TerminalDevice->InputState; + + if (IsEfiKeyFiFoFull (TerminalDevice)) { + return; + } - if (TerminalDevice->InputState & INPUT_STATE_ESC) { + if ((InputState & INPUT_STATE_ESC) != 0) { Key.ScanCode = SCAN_ESC; Key.UnicodeChar = 0; - EfiKeyFiFoInsertOneKey (TerminalDevice, Key); + EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); } - if (TerminalDevice->InputState & INPUT_STATE_CSI) { + if ((InputState & INPUT_STATE_CSI) != 0) { Key.ScanCode = SCAN_NULL; Key.UnicodeChar = CSI; - EfiKeyFiFoInsertOneKey (TerminalDevice, Key); + EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); } - if (TerminalDevice->InputState & INPUT_STATE_LEFTOPENBRACKET) { + if ((InputState & INPUT_STATE_LEFTOPENBRACKET) != 0) { Key.ScanCode = SCAN_NULL; Key.UnicodeChar = LEFTOPENBRACKET; - EfiKeyFiFoInsertOneKey (TerminalDevice, Key); + EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); } - if (TerminalDevice->InputState & INPUT_STATE_O) { + if ((InputState & INPUT_STATE_O) != 0) { Key.ScanCode = SCAN_NULL; Key.UnicodeChar = 'O'; - EfiKeyFiFoInsertOneKey (TerminalDevice, Key); + EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); } - if (TerminalDevice->InputState & INPUT_STATE_2) { + if ((InputState & INPUT_STATE_2) != 0) { Key.ScanCode = SCAN_NULL; Key.UnicodeChar = '2'; - EfiKeyFiFoInsertOneKey (TerminalDevice, Key); + EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); } + // + // Cancel the timer. + // gBS->SetTimer ( TerminalDevice->TwoSecondTimeOut, TimerCancel, @@ -1124,87 +1258,85 @@ UnicodeToEfiKeyFlushState ( 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 ) -/*++ - Routine Description: - - Converts a stream of Unicode characters from a terminal input device into EFI Keys that - can be read through the Simple Input Protocol. The table below shows the keyboard - input mappings that this function supports. If the ESC sequence listed in one of the - columns is presented, then it is translated into the coorespoding EFI Scan Code. If a - matching sequence is not found, then the raw key strokes are converted into EFI Keys. - - 2 seconds are allowed for an ESC sequence to be completed. If the ESC sequence is not - completed in 2 seconds, then the raw key strokes of the partial ESC sequence are - converted into EFI Keys. - - There is one special input sequence that will force the system to reset. - This is ESC R ESC r ESC R. - - Arguments: - - TerminaDevice : The terminal device to use to translate raw input into EFI Keys - - Returns: - - None - -Symbols used in table below -=========================== - ESC = 0x1B - CSI = 0x9B - DEL = 0x7f - ^ = CTRL - -+=========+======+===========+==========+==========+ -| | EFI | EFI 1.10 | | | -| | Scan | | VT100+ | | -| KEY | Code | PC ANSI | VTUTF8 | VT100 | -+=========+======+===========+==========+==========+ -| NULL | 0x00 | | | | -| UP | 0x01 | ESC [ A | ESC [ A | ESC [ A | -| DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B | -| RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C | -| LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D | -| HOME | 0x05 | ESC [ H | ESC h | ESC [ H | -| END | 0x06 | ESC [ F | ESC k | ESC [ K | -| INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ | -| | | ESC [ L | | ESC [ L | -| DELETE | 0x08 | ESC [ X | ESC - | ESC [ P | -| PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V | -| | | | | ESC [ ? | -| PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U | -| | | | | ESC [ / | -| F1 | 0x0B | ESC [ M | ESC 1 | ESC O P | -| F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q | -| F3 | 0x0D | ESC [ O | ESC 3 | ESC O w | -| F4 | 0x0E | ESC [ P | ESC 4 | ESC O x | -| F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t | -| F6 | 0x10 | ESC [ R | ESC 6 | ESC O u | -| F7 | 0x11 | ESC [ S | ESC 7 | ESC O q | -| F8 | 0x12 | ESC [ T | ESC 8 | ESC O r | -| F9 | 0x13 | ESC [ U | ESC 9 | ESC O p | -| F10 | 0x14 | ESC [ V | ESC 0 | ESC O M | -| Escape | 0x17 | ESC | ESC | ESC | -| F11 | 0x15 | | ESC ! | | -| F12 | 0x16 | | ESC @ | | -+=========+======+===========+==========+==========+ - -Special Mappings -================ -ESC R ESC r ESC R = Reset System - ---*/ { EFI_STATUS Status; EFI_STATUS TimerStatus; UINT16 UnicodeChar; EFI_INPUT_KEY Key; BOOLEAN SetDefaultResetState; - + TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut); if (!EFI_ERROR (TimerStatus)) { @@ -1212,11 +1344,11 @@ ESC R ESC r ESC R = Reset System TerminalDevice->ResetState = RESET_STATE_DEFAULT; } - while (!IsUnicodeFiFoEmpty(TerminalDevice)) { - + while (!IsUnicodeFiFoEmpty (TerminalDevice) && !IsEfiKeyFiFoFull (TerminalDevice)) { + if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) { // - // Check to see if the 2 second timer has expired + // Check to see if the 2 seconds timer has expired // TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut); if (!EFI_ERROR (TimerStatus)) { @@ -1228,7 +1360,7 @@ ESC R ESC r ESC R = Reset System // // Fetch one Unicode character from the Unicode FIFO // - UnicodeFiFoRemoveOneKey (TerminalDevice,&UnicodeChar); + UnicodeFiFoRemoveOneKey (TerminalDevice, &UnicodeChar); SetDefaultResetState = TRUE; @@ -1245,94 +1377,95 @@ ESC R ESC r ESC R = Reset System continue; } - if (UnicodeChar == 'O' && TerminalDevice->TerminalType == VT100Type) { + if (UnicodeChar == 'O' && (TerminalDevice->TerminalType == TerminalTypeVt100 || + TerminalDevice->TerminalType == TerminalTypeTtyTerm)) { TerminalDevice->InputState |= INPUT_STATE_O; TerminalDevice->ResetState = RESET_STATE_DEFAULT; continue; } Key.ScanCode = SCAN_NULL; - - if (TerminalDevice->TerminalType == VT100PlusType || - TerminalDevice->TerminalType == VTUTF8Type) { + + if (TerminalDevice->TerminalType == TerminalTypeVt100Plus || + TerminalDevice->TerminalType == TerminalTypeVtUtf8) { switch (UnicodeChar) { - case '1': - Key.ScanCode = SCAN_F1; + case '1': + Key.ScanCode = SCAN_F1; break; - case '2': - Key.ScanCode = SCAN_F2; + case '2': + Key.ScanCode = SCAN_F2; break; - case '3': - Key.ScanCode = SCAN_F3; + case '3': + Key.ScanCode = SCAN_F3; break; - case '4': - Key.ScanCode = SCAN_F4; + case '4': + Key.ScanCode = SCAN_F4; break; - case '5': - Key.ScanCode = SCAN_F5; + case '5': + Key.ScanCode = SCAN_F5; break; - case '6': - Key.ScanCode = SCAN_F6; + case '6': + Key.ScanCode = SCAN_F6; break; - case '7': - Key.ScanCode = SCAN_F7; + case '7': + Key.ScanCode = SCAN_F7; break; - case '8': - Key.ScanCode = SCAN_F8; + case '8': + Key.ScanCode = SCAN_F8; break; - case '9': - Key.ScanCode = SCAN_F9; + case '9': + Key.ScanCode = SCAN_F9; break; - case '0': - Key.ScanCode = SCAN_F10; + 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; + case 'h': + Key.ScanCode = SCAN_HOME; break; - case '+': - Key.ScanCode = SCAN_INSERT; + case 'k': + Key.ScanCode = SCAN_END; break; - case '-': - Key.ScanCode = SCAN_DELETE; + case '+': + Key.ScanCode = SCAN_INSERT; break; - case '/': - Key.ScanCode = SCAN_PAGE_DOWN; + case '-': + Key.ScanCode = SCAN_DELETE; break; - case '?': - Key.ScanCode = SCAN_PAGE_UP; - break; - default : + case '/': + Key.ScanCode = SCAN_PAGE_DOWN; + break; + case '?': + Key.ScanCode = SCAN_PAGE_UP; + break; + default : break; } } - + switch (UnicodeChar) { - case 'R': + 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) { + } else if (TerminalDevice->ResetState == RESET_STATE_ESC_R_ESC_R) { gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL); } Key.ScanCode = SCAN_NULL; break; - case 'r': + case 'r': if (TerminalDevice->ResetState == RESET_STATE_ESC_R) { - TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_r; + TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_R; SetDefaultResetState = FALSE; } Key.ScanCode = SCAN_NULL; break; - default : + default : break; } @@ -1342,7 +1475,7 @@ ESC R ESC r ESC R = Reset System if (Key.ScanCode != SCAN_NULL) { Key.UnicodeChar = 0; - EfiKeyFiFoInsertOneKey (TerminalDevice,Key); + EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); TerminalDevice->InputState = INPUT_STATE_DEFAULT; UnicodeToEfiKeyFlushState (TerminalDevice); continue; @@ -1357,47 +1490,69 @@ ESC R ESC r ESC R = Reset System TerminalDevice->ResetState = RESET_STATE_DEFAULT; Key.ScanCode = SCAN_NULL; - - if (TerminalDevice->TerminalType == VT100Type) { + + if (TerminalDevice->TerminalType == TerminalTypeVt100) { switch (UnicodeChar) { - case 'P': - Key.ScanCode = SCAN_F1; + 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_F2; + case 'q': + Key.ScanCode = SCAN_F7; break; - case 'w': - Key.ScanCode = SCAN_F3; + case 'r': + Key.ScanCode = SCAN_F8; break; - case 'x': - Key.ScanCode = SCAN_F4; + case 'p': + Key.ScanCode = SCAN_F9; break; - case 't': - Key.ScanCode = SCAN_F5; + case 'M': + Key.ScanCode = SCAN_F10; break; - case 'u': - Key.ScanCode = SCAN_F6; + default : break; - case 'q': - Key.ScanCode = SCAN_F7; + } + } else if (TerminalDevice->TerminalType == TerminalTypeTtyTerm) { + /* Also accept VT100 escape codes for F1-F4, HOME and END for TTY term */ + switch (UnicodeChar) { + case 'P': + Key.ScanCode = SCAN_F1; + break; + case 'Q': + Key.ScanCode = SCAN_F2; break; - case 'r': - Key.ScanCode = SCAN_F8; + case 'R': + Key.ScanCode = SCAN_F3; break; - case 'p': - Key.ScanCode = SCAN_F9; + case 'S': + Key.ScanCode = SCAN_F4; break; - case 'M': - Key.ScanCode = SCAN_F10; + case 'H': + Key.ScanCode = SCAN_HOME; break; - default : + case 'F': + Key.ScanCode = SCAN_END; break; } } if (Key.ScanCode != SCAN_NULL) { Key.UnicodeChar = 0; - EfiKeyFiFoInsertOneKey (TerminalDevice,Key); + EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); TerminalDevice->InputState = INPUT_STATE_DEFAULT; UnicodeToEfiKeyFlushState (TerminalDevice); continue; @@ -1408,134 +1563,154 @@ ESC R ESC r ESC R = Reset System 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) { + + if (TerminalDevice->TerminalType == TerminalTypePcAnsi || + TerminalDevice->TerminalType == TerminalTypeVt100 || + TerminalDevice->TerminalType == TerminalTypeVt100Plus || + TerminalDevice->TerminalType == TerminalTypeVtUtf8 || + TerminalDevice->TerminalType == TerminalTypeTtyTerm) { switch (UnicodeChar) { - case 'A': - Key.ScanCode = SCAN_UP; + case 'A': + Key.ScanCode = SCAN_UP; break; - case 'B': - Key.ScanCode = SCAN_DOWN; + case 'B': + Key.ScanCode = SCAN_DOWN; break; - case 'C': - Key.ScanCode = SCAN_RIGHT; + case 'C': + Key.ScanCode = SCAN_RIGHT; break; - case 'D': - Key.ScanCode = SCAN_LEFT; + case 'D': + Key.ScanCode = SCAN_LEFT; break; - case 'H': - if (TerminalDevice->TerminalType == PcAnsiType || - TerminalDevice->TerminalType == VT100Type) { - Key.ScanCode = SCAN_HOME; + case 'H': + if (TerminalDevice->TerminalType == TerminalTypePcAnsi || + TerminalDevice->TerminalType == TerminalTypeVt100 || + TerminalDevice->TerminalType == TerminalTypeTtyTerm) { + Key.ScanCode = SCAN_HOME; } break; - case 'F': - if (TerminalDevice->TerminalType == PcAnsiType) { + case 'F': + if (TerminalDevice->TerminalType == TerminalTypePcAnsi || + TerminalDevice->TerminalType == TerminalTypeTtyTerm) { Key.ScanCode = SCAN_END; } break; - case 'K': - if (TerminalDevice->TerminalType == VT100Type) { - Key.ScanCode = SCAN_END; + case 'K': + if (TerminalDevice->TerminalType == TerminalTypeVt100) { + Key.ScanCode = SCAN_END; } break; - case 'L': - case '@': - if (TerminalDevice->TerminalType == PcAnsiType || - TerminalDevice->TerminalType == VT100Type) { - Key.ScanCode = SCAN_INSERT; + case 'L': + case '@': + if (TerminalDevice->TerminalType == TerminalTypePcAnsi || + TerminalDevice->TerminalType == TerminalTypeVt100) { + Key.ScanCode = SCAN_INSERT; } break; - case 'X': - if (TerminalDevice->TerminalType == PcAnsiType) { + case 'X': + if (TerminalDevice->TerminalType == TerminalTypePcAnsi) { Key.ScanCode = SCAN_DELETE; } break; - case 'P': - if (TerminalDevice->TerminalType == VT100Type) { - Key.ScanCode = SCAN_DELETE; - } else if (TerminalDevice->TerminalType == PcAnsiType) { + case 'P': + if (TerminalDevice->TerminalType == TerminalTypeVt100) { + Key.ScanCode = SCAN_DELETE; + } else if (TerminalDevice->TerminalType == TerminalTypePcAnsi) { Key.ScanCode = SCAN_F4; } break; - case 'I': - if (TerminalDevice->TerminalType == PcAnsiType) { + case 'I': + if (TerminalDevice->TerminalType == TerminalTypePcAnsi) { Key.ScanCode = SCAN_PAGE_UP; } - break; - case 'V': - if (TerminalDevice->TerminalType == PcAnsiType) { + break; + case 'V': + if (TerminalDevice->TerminalType == TerminalTypePcAnsi) { Key.ScanCode = SCAN_F10; - } - case '?': - if (TerminalDevice->TerminalType == VT100Type) { - Key.ScanCode = SCAN_PAGE_UP; } break; - case 'G': - if (TerminalDevice->TerminalType == PcAnsiType) { + case '?': + if (TerminalDevice->TerminalType == TerminalTypeVt100) { + Key.ScanCode = SCAN_PAGE_UP; + } + break; + case 'G': + if (TerminalDevice->TerminalType == TerminalTypePcAnsi) { Key.ScanCode = SCAN_PAGE_DOWN; } - break; - case 'U': - if (TerminalDevice->TerminalType == PcAnsiType) { + break; + case 'U': + if (TerminalDevice->TerminalType == TerminalTypePcAnsi) { Key.ScanCode = SCAN_F9; } - case '/': - if (TerminalDevice->TerminalType == VT100Type) { - Key.ScanCode = SCAN_PAGE_DOWN; + break; + case '/': + if (TerminalDevice->TerminalType == TerminalTypeVt100) { + Key.ScanCode = SCAN_PAGE_DOWN; } break; - case 'M': - if (TerminalDevice->TerminalType == PcAnsiType) { + case 'M': + if (TerminalDevice->TerminalType == TerminalTypePcAnsi) { Key.ScanCode = SCAN_F1; } - break; - case 'N': - if (TerminalDevice->TerminalType == PcAnsiType) { + break; + case 'N': + if (TerminalDevice->TerminalType == TerminalTypePcAnsi) { Key.ScanCode = SCAN_F2; } - break; - case 'O': - if (TerminalDevice->TerminalType == PcAnsiType) { + break; + case 'O': + if (TerminalDevice->TerminalType == TerminalTypePcAnsi) { Key.ScanCode = SCAN_F3; } - break; - case 'Q': - if (TerminalDevice->TerminalType == PcAnsiType) { + break; + case 'Q': + if (TerminalDevice->TerminalType == TerminalTypePcAnsi) { Key.ScanCode = SCAN_F5; } - break; - case 'R': - if (TerminalDevice->TerminalType == PcAnsiType) { + break; + case 'R': + if (TerminalDevice->TerminalType == TerminalTypePcAnsi) { Key.ScanCode = SCAN_F6; } - break; - case 'S': - if (TerminalDevice->TerminalType == PcAnsiType) { + break; + case 'S': + if (TerminalDevice->TerminalType == TerminalTypePcAnsi) { Key.ScanCode = SCAN_F7; } - break; - case 'T': - if (TerminalDevice->TerminalType == PcAnsiType) { + break; + case 'T': + if (TerminalDevice->TerminalType == TerminalTypePcAnsi) { Key.ScanCode = SCAN_F8; } - break; - default : + break; + default : break; } } + /* + * The VT220 escape codes that the TTY terminal accepts all have + * numeric codes, and there are no ambiguous prefixes shared with + * other terminal types. + */ + if (TerminalDevice->TerminalType == TerminalTypeTtyTerm && + Key.ScanCode == SCAN_NULL && + UnicodeChar >= '0' && + UnicodeChar <= '9') { + TerminalDevice->TtyEscapeStr[0] = UnicodeChar; + TerminalDevice->TtyEscapeIndex = 1; + TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET_2; + continue; + } + if (Key.ScanCode != SCAN_NULL) { Key.UnicodeChar = 0; - EfiKeyFiFoInsertOneKey (TerminalDevice,Key); + EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); TerminalDevice->InputState = INPUT_STATE_DEFAULT; UnicodeToEfiKeyFlushState (TerminalDevice); continue; @@ -1545,7 +1720,75 @@ ESC R ESC r ESC R = Reset System break; - + + case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET | INPUT_STATE_LEFTOPENBRACKET_2: + /* + * Here we handle the VT220 escape codes that we accept. This + * state is only used by the TTY terminal type. + */ + Key.ScanCode = SCAN_NULL; + if (TerminalDevice->TerminalType == TerminalTypeTtyTerm) { + + if (UnicodeChar == '~' && TerminalDevice->TtyEscapeIndex <= 2) { + UINT16 EscCode; + TerminalDevice->TtyEscapeStr[TerminalDevice->TtyEscapeIndex] = 0; /* Terminate string */ + EscCode = (UINT16) StrDecimalToUintn(TerminalDevice->TtyEscapeStr); + switch (EscCode) { + case 2: + Key.ScanCode = SCAN_INSERT; + break; + case 3: + Key.ScanCode = SCAN_DELETE; + break; + case 5: + Key.ScanCode = SCAN_PAGE_UP; + break; + case 6: + Key.ScanCode = SCAN_PAGE_DOWN; + break; + case 11: + case 12: + case 13: + case 14: + case 15: + Key.ScanCode = SCAN_F1 + EscCode - 11; + break; + case 17: + case 18: + case 19: + case 20: + case 21: + Key.ScanCode = SCAN_F6 + EscCode - 17; + break; + case 23: + case 24: + Key.ScanCode = SCAN_F11 + EscCode - 23; + break; + default: + break; + } + } else if (TerminalDevice->TtyEscapeIndex == 1){ + /* 2 character escape code */ + TerminalDevice->TtyEscapeStr[TerminalDevice->TtyEscapeIndex++] = UnicodeChar; + continue; + } + else { + DEBUG ((EFI_D_ERROR, "Unexpected state in escape2\n")); + } + } + 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; + default: // // Invalid state. This should never happen. @@ -1564,7 +1807,7 @@ ESC R ESC r ESC R = Reset System if (UnicodeChar == CSI) { TerminalDevice->InputState = INPUT_STATE_CSI; } - + if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) { Status = gBS->SetTimer( TerminalDevice->TwoSecondTimeOut, @@ -1580,13 +1823,19 @@ ESC R ESC r ESC R = Reset System } if (UnicodeChar == DEL) { - Key.ScanCode = SCAN_DELETE; - Key.UnicodeChar = 0; + if (TerminalDevice->TerminalType == TerminalTypeTtyTerm) { + Key.ScanCode = SCAN_NULL; + Key.UnicodeChar = CHAR_BACKSPACE; + } + else { + Key.ScanCode = SCAN_DELETE; + Key.UnicodeChar = 0; + } } else { Key.ScanCode = SCAN_NULL; Key.UnicodeChar = UnicodeChar; } - EfiKeyFiFoInsertOneKey (TerminalDevice,Key); + EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); } }