Calculate serial input polling rate according to parameters from serial IO mode as below, to fix potential input truncation with fixed polling interval 0.02s.
Polling interval (100ns) = FifoDepth * (ParityBits + StopBits + DataBits) * 10,000,000 / BaudRate However, as UEFI events will probably delayed by other code of higher TPL, we use below equation to make polling rate fast enough: FifoDepth * DataBits * 10,000,000 * 2 / (BaudRate * 3) Signed-off-by: Heyi Guo <[email protected]> Cc: Feng Tian <[email protected]> Cc: Star Zeng <[email protected]> --- .../Universal/Console/TerminalDxe/Terminal.c | 5 +- .../Universal/Console/TerminalDxe/Terminal.h | 27 ++++++++- .../Universal/Console/TerminalDxe/TerminalConIn.c | 68 ++++++++++++++++++++++ 3 files changed, 98 insertions(+), 2 deletions(-) diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c index 5adaa97..db790f3 100644 --- a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c +++ b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c @@ -71,6 +71,7 @@ TERMINAL_DEV mTerminalDevTemplate = { }, NULL, // TerminalConsoleModeData 0, // SerialInTimeOut + DEFAULT_KEYBOARD_TIMER_INTERVAL, // KeyboardTimerInterval NULL, // RawFifo NULL, // UnicodeFiFo @@ -984,10 +985,12 @@ TerminalDriverBindingStart ( ); ASSERT_EFI_ERROR (Status); + TerminalDevice->KeyboardTimerInterval = GetKeyboardTimerInterval (Mode); + Status = gBS->SetTimer ( TerminalDevice->TimerEvent, TimerPeriodic, - KEYBOARD_TIMER_INTERVAL + TerminalDevice->KeyboardTimerInterval ); ASSERT_EFI_ERROR (Status); diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h index 269d2ae..58d5664 100644 --- a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h +++ b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h @@ -68,7 +68,7 @@ typedef struct { UINTN Rows; } TERMINAL_CONSOLE_MODE_DATA; -#define KEYBOARD_TIMER_INTERVAL 200000 // 0.02s +#define DEFAULT_KEYBOARD_TIMER_INTERVAL 200000 // 0.02s #define TERMINAL_DEV_SIGNATURE SIGNATURE_32 ('t', 'm', 'n', 'l') @@ -91,6 +91,7 @@ typedef struct { EFI_SIMPLE_TEXT_OUTPUT_MODE SimpleTextOutputMode; TERMINAL_CONSOLE_MODE_DATA *TerminalConsoleModeData; UINTN SerialInTimeOut; + UINT64 KeyboardTimerInterval; RAW_DATA_FIFO *RawFiFo; UNICODE_FIFO *UnicodeFiFo; EFI_KEY_FIFO *EfiKeyFiFo; @@ -1358,4 +1359,28 @@ TerminalConInTimerHandler ( IN EFI_EVENT Event, IN VOID *Context ); + +/** + Calculate input polling timer interval by serial IO mode. + + @param Mode Pointer to serial IO mode. + + @retval The required polling timer interval in 100ns. + +**/ +UINT64 +GetKeyboardTimerInterval ( + IN EFI_SERIAL_IO_MODE *Mode + ); + +/** + Update period of polling timer event. + + @param TerminalDevice The terminal device to update. +**/ +VOID +UpdatePollingRate ( + IN TERMINAL_DEV *TerminalDevice + ); + #endif diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c index 2215df6..22349a0 100644 --- a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c +++ b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c @@ -502,6 +502,71 @@ TerminalConInWaitForKey ( } /** + Calculate input polling timer interval by serial IO mode. + + @param Mode Pointer to serial IO mode. + + @retval The required polling timer interval in 100ns. + +**/ +UINT64 +GetKeyboardTimerInterval ( + IN EFI_SERIAL_IO_MODE *Mode + ) +{ + UINT32 FifoDepth; + + if (Mode->BaudRate == 0) { + return DEFAULT_KEYBOARD_TIMER_INTERVAL; + } + + FifoDepth = Mode->ReceiveFifoDepth; + // Fix incorrect FIFO depth + if (FifoDepth == 0) { + FifoDepth = 1; + } + + // We ignore stop bits and parity bit, and reduce the interval by 1/3, + // to make polling rate fast enough to avoid serial input truncation. + return DivU64x64Remainder ( + FifoDepth * Mode->DataBits * 10000000 * 2, + Mode->BaudRate * 3, + NULL + ); +} + + +/** + Update period of polling timer event. + + @param TerminalDevice The terminal device to update. +**/ +VOID +UpdatePollingRate ( + IN TERMINAL_DEV *TerminalDevice + ) +{ + UINT64 NewInterval; + EFI_STATUS Status; + + NewInterval = GetKeyboardTimerInterval (TerminalDevice->SerialIo->Mode); + + if (TerminalDevice->KeyboardTimerInterval == NewInterval) { + return; + } + + Status = gBS->SetTimer ( + TerminalDevice->TimerEvent, + TimerPeriodic, + NewInterval + ); + ASSERT_EFI_ERROR (Status); + + TerminalDevice->KeyboardTimerInterval = NewInterval; +} + + +/** Timer handler to poll the key from serial. @param Event Indicates the event that invoke this function. @@ -560,6 +625,9 @@ TerminalConInTimerHandler ( TerminalDevice->SerialInTimeOut = SerialInTimeOut; } } + + UpdatePollingRate (TerminalDevice); + // // Check whether serial buffer is empty. // Skip the key transfer loop only if the SerialIo protocol instance -- 2.7.0 _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

