git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@8028 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1615 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1615 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol.
 | |
| 
 | |
| Copyright (c) 2006 - 2008, Intel Corporation. <BR>
 | |
| 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_DEVICE_ERROR         The keystroke information was not returned due
 | |
|                                    to hardware errors.
 | |
|   @retval EFI_INVALID_PARAMETER    KeyData is NULL.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ReadKeyStrokeWorker (
 | |
|   IN  TERMINAL_DEV *TerminalDevice,
 | |
|   OUT EFI_KEY_DATA *KeyData
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   LIST_ENTRY                      *Link;
 | |
|   LIST_ENTRY                      *NotifyList;
 | |
|   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
 | |
|   //
 | |
|   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);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   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,
 | |
|     PcdGet32 (PcdStatusCodeValueRemoteConsoleReset),
 | |
|     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,
 | |
|       PcdGet32 (PcdStatusCodeValueRemoteConsoleError),
 | |
|       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
 | |
|   )
 | |
| {
 | |
|   TERMINAL_DEV            *TerminalDevice;
 | |
| 
 | |
|   TerminalDevice  = TERMINAL_CON_IN_EX_DEV_FROM_THIS (Context);
 | |
| 
 | |
|   TerminalConInWaitForKey (Event, &TerminalDevice->SimpleInput);
 | |
| 
 | |
| }
 | |
| 
 | |
| //
 | |
| // 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
 | |
|   //
 | |
|   // Context is the pointer to EFI_SIMPLE_TEXT_INPUT_PROTOCOL
 | |
|   //
 | |
|   if (!EFI_ERROR (TerminalConInCheckForKey (Context))) {
 | |
| 
 | |
|     gBS->SignalEvent (Event);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Check for a pending key in the Efi Key FIFO or Serial device buffer.
 | |
| 
 | |
|   @param  This                     Indicates the calling context.
 | |
| 
 | |
|   @retval EFI_SUCCESS              There is key pending.
 | |
|   @retval EFI_NOT_READY            There is no key pending.
 | |
|   @retval EFI_DEVICE_ERROR         If Serial IO is not attached to serial device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| TerminalConInCheckForKey (
 | |
|   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   TERMINAL_DEV            *TerminalDevice;
 | |
|   UINT32                  Control;
 | |
|   UINT8                   Input;
 | |
|   EFI_SERIAL_IO_MODE      *Mode;
 | |
|   EFI_SERIAL_IO_PROTOCOL  *SerialIo;
 | |
|   UINTN                   SerialInTimeOut;
 | |
| 
 | |
|   TerminalDevice  = TERMINAL_CON_IN_DEV_FROM_THIS (This);
 | |
| 
 | |
|   SerialIo        = TerminalDevice->SerialIo;
 | |
|   if (SerialIo == NULL) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
|   //
 | |
|   //  if current timeout value for serial device is not identical with
 | |
|   //  the value saved in TERMINAL_DEV structure, then recalculate the
 | |
|   //  timeout value again and set serial attribute according to this value.
 | |
|   //
 | |
|   Mode = SerialIo->Mode;
 | |
|   if (Mode->Timeout != TerminalDevice->SerialInTimeOut) {
 | |
| 
 | |
|     SerialInTimeOut = 0;
 | |
|     if (Mode->BaudRate != 0) {
 | |
|       //
 | |
|       // 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;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   //  Check whether serial buffer is empty.
 | |
|   //
 | |
|   Status = SerialIo->GetControl (SerialIo, &Control);
 | |
| 
 | |
|   if ((Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) != 0) {
 | |
|     //
 | |
|     // Translate all the raw data in RawFIFO into EFI Key,
 | |
|     // according to different terminal type supported.
 | |
|     //
 | |
|     TranslateRawDataToEfiKey (TerminalDevice);
 | |
| 
 | |
|     //
 | |
|     //  if there is pre-fetched Efi Key in EfiKeyFIFO buffer,
 | |
|     //  return directly.
 | |
|     //
 | |
|     if (!IsEfiKeyFiFoEmpty (TerminalDevice)) {
 | |
|       return EFI_SUCCESS;
 | |
|     } else {
 | |
|       return EFI_NOT_READY;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Fetch all the keys in the serial buffer,
 | |
|   // and insert the byte stream into RawFIFO.
 | |
|   //
 | |
|   do {
 | |
| 
 | |
|     Status = GetOneKeyFromSerial (TerminalDevice->SerialIo, &Input);
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       if (Status == EFI_DEVICE_ERROR) {
 | |
|         REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | |
|           EFI_ERROR_CODE | EFI_ERROR_MINOR,
 | |
|           PcdGet32 (PcdStatusCodeValueRemoteConsoleInputError),
 | |
|           TerminalDevice->DevicePath
 | |
|           );
 | |
|       }
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     RawFiFoInsertOneKey (TerminalDevice, Input);
 | |
|   } while (TRUE);
 | |
| 
 | |
|   //
 | |
|   // Translate all the raw data in RawFIFO into EFI Key,
 | |
|   // according to different terminal type supported.
 | |
|   //
 | |
|   TranslateRawDataToEfiKey (TerminalDevice);
 | |
| 
 | |
|   if (IsEfiKeyFiFoEmpty (TerminalDevice)) {
 | |
|     return EFI_NOT_READY;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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;
 | |
| 
 | |
|   Tail = TerminalDevice->EfiKeyFiFo->Tail;
 | |
|   ASSERT (Tail < FIFO_MAX_NUMBER + 1);
 | |
| 
 | |
|   if (IsEfiKeyFiFoFull (TerminalDevice)) {
 | |
|     //
 | |
|     // Efi Key FIFO is full
 | |
|     //
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   TerminalDevice->EfiKeyFiFo->Data[Tail] = Key;
 | |
| 
 | |
|   TerminalDevice->EfiKeyFiFo->Tail       = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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.
 | |
| 
 | |
|   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);
 | |
|   }
 | |
| }
 |