/** @file\r
SerialIo implementation for PCI or SIO UARTs.\r
\r
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>\r
SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Flush the serial hardware transmit FIFO, holding register, and shift register.\r
+\r
+ @param SerialDevice The device to flush.\r
+\r
+ @retval EFI_SUCCESS The transmit FIFO is completely flushed.\r
+ @retval EFI_TIMEOUT A timeout occured waiting for the transmit FIFO to flush.\r
+**/\r
+EFI_STATUS\r
+SerialFlushTransmitFifo (\r
+ SERIAL_DEV *SerialDevice\r
+ )\r
+{\r
+ SERIAL_PORT_LSR Lsr;\r
+ UINTN Timeout;\r
+ UINTN Elapsed;\r
+\r
+ //\r
+ // If this is the first time the UART is being configured, then the current\r
+ // UART settings are not known, so compute a timeout to wait for the Tx FIFO\r
+ // assuming the worst case current settings.\r
+ //\r
+ // Timeout = (Max Bits per Char) * (Max Pending Chars) / (Slowest Baud Rate)\r
+ // Max Bits per Char = Start bit + 8 data bits + parity + 2 stop bits = 12\r
+ // Max Pending Chars = Largest Tx FIFO + hold + shift = 64 + 1 + 1 = 66\r
+ // Slowest Reasonable Baud Rate = 300 baud\r
+ // Timeout = 12 * 66 / 300 = 2.64 seconds = 2,640,000 uS\r
+ //\r
+ Timeout = 2640000;\r
+\r
+ //\r
+ // Use the largest of the computed timeout, the default timeout, and the\r
+ // currently set timeout.\r
+ //\r
+ Timeout = MAX (Timeout, SERIAL_PORT_DEFAULT_TIMEOUT);\r
+ Timeout = MAX (Timeout, SerialDevice->SerialMode.Timeout);\r
+\r
+ //\r
+ // Wait for the shortest time possible for the serial port to be ready making\r
+ // sure the transmit FIFO, holding register, and shift register are all\r
+ // empty. The actual wait time is expected to be very small because the\r
+ // number characters currently in the FIFO should be small when a\r
+ // configuration change is requested.\r
+ //\r
+ // NOTE: Do not use any DEBUG() or REPORT_STATUS_CODE() or any other calls\r
+ // in the rest of this function that may send additional characters to this\r
+ // UART device invalidating the flush operation.\r
+ //\r
+ Elapsed = 0;\r
+ Lsr.Data = READ_LSR (SerialDevice);\r
+ while (Lsr.Bits.Temt == 0 || Lsr.Bits.Thre == 0) {\r
+ if (Elapsed >= Timeout) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+ gBS->Stall (TIMEOUT_STALL_INTERVAL);\r
+ Elapsed += TIMEOUT_STALL_INTERVAL;\r
+ Lsr.Data = READ_LSR (SerialDevice);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
//\r
// Interface Functions\r
//\r
\r
Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
\r
+ //\r
+ // Wait for all data to be transmitted before changing the UART configuration.\r
+ //\r
+ // NOTE: Do not use any DEBUG() or REPORT_STATUS_CODE() or any other calls\r
+ // that may send additional characters to this UART device until the UART\r
+ // configuration change is complete.\r
+ //\r
+ SerialFlushTransmitFifo (SerialDevice);\r
+\r
//\r
// Make sure DLAB is 0.\r
//\r
\r
Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
\r
+ //\r
+ // Wait for all data to be transmitted before changing the UART configuration.\r
+ //\r
+ // NOTE: Do not use any DEBUG() or REPORT_STATUS_CODE() or any other calls\r
+ // that may send additional characters to this UART device until the UART\r
+ // configuration change is complete.\r
+ //\r
+ SerialFlushTransmitFifo (SerialDevice);\r
+\r
//\r
// Put serial port on Divisor Latch Mode\r
//\r
\r
Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
\r
+ //\r
+ // Wait for all data to be transmitted before changing the UART configuration.\r
+ //\r
+ // NOTE: Do not use any DEBUG() or REPORT_STATUS_CODE() or any other calls\r
+ // that may send additional characters to this UART device until the UART\r
+ // configuration change is complete.\r
+ //\r
+ SerialFlushTransmitFifo (SerialDevice);\r
+\r
Mcr.Data = READ_MCR (SerialDevice);\r
Mcr.Bits.DtrC = 0;\r
Mcr.Bits.Rts = 0;\r