+/** @file\r
+ Install Serial IO Protocol that layers on top of a Debug Communication Library instance.\r
+\r
+ Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "DxeDebugAgentLib.h"\r
+\r
+//\r
+// Serial I/O Protocol Interface defintions.\r
+//\r
+\r
+/**\r
+ Reset serial device.\r
+\r
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
+\r
+ @retval EFI_SUCCESS Reset successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialReset (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This\r
+ );\r
+ \r
+/**\r
+ Set new attributes to a serial device.\r
+\r
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
+ @param[in] BaudRate The baudrate of the serial device.\r
+ @param[in] ReceiveFifoDepth The depth of receive FIFO buffer.\r
+ @param[in] Timeout The request timeout for a single char.\r
+ @param[in] Parity The type of parity used in serial device.\r
+ @param[in] DataBits Number of databits used in serial device.\r
+ @param[in] StopBits Number of stopbits used in serial device.\r
+\r
+ @retval EFI_SUCCESS The new attributes were set.\r
+ @retval EFI_INVALID_PARAMETER One or more attributes have an unsupported value.\r
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return).\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialSetAttributes (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN UINT64 BaudRate,\r
+ IN UINT32 ReceiveFifoDepth,\r
+ IN UINT32 Timeout,\r
+ IN EFI_PARITY_TYPE Parity,\r
+ IN UINT8 DataBits,\r
+ IN EFI_STOP_BITS_TYPE StopBits\r
+ );\r
+\r
+/**\r
+ Set Control Bits.\r
+\r
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
+ @param[in] Control Control bits that can be settable.\r
+\r
+ @retval EFI_SUCCESS New Control bits were set successfully.\r
+ @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialSetControl (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN UINT32 Control\r
+ );\r
+\r
+/**\r
+ Get ControlBits.\r
+\r
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
+ @param[out] Control Control signals of the serial device.\r
+\r
+ @retval EFI_SUCCESS Get Control signals successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialGetControl (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ OUT UINT32 *Control\r
+ );\r
+\r
+/**\r
+ Write the specified number of bytes to serial device.\r
+\r
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
+ @param[in, out] BufferSize On input the size of Buffer, on output the amount of\r
+ data actually written.\r
+ @param[in] Buffer The buffer of data to write.\r
+\r
+ @retval EFI_SUCCESS The data were written successfully.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_TIMEOUT The write operation was stopped due to timeout.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialWrite (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN OUT UINTN *BufferSize,\r
+ IN VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Read the specified number of bytes from serial device.\r
+\r
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
+ @param[in, out] BufferSize On input the size of Buffer, on output the amount of\r
+ data returned in buffer.\r
+ @param[out] Buffer The buffer to return the data into.\r
+\r
+ @retval EFI_SUCCESS The data were read successfully.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_TIMEOUT The read operation was stopped due to timeout.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialRead (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+//\r
+// Serial Driver Defaults\r
+//\r
+#define SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH 1\r
+#define SERIAL_PORT_DEFAULT_TIMEOUT 1000000\r
+#define SERIAL_PORT_DEFAULT_CONTROL_MASK 0\r
+#define SERIAL_PORT_LOOPBACK_BUFFER_FULL BIT8\r
+\r
+//\r
+// EFI_SERIAL_IO_MODE instance\r
+//\r
+EFI_SERIAL_IO_MODE mSerialIoMode = {\r
+ SERIAL_PORT_DEFAULT_CONTROL_MASK,\r
+ SERIAL_PORT_DEFAULT_TIMEOUT,\r
+ 0, // BaudRate\r
+ SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH,\r
+ 0, // DataBits\r
+ 0, // Parity\r
+ 0 // StopBits\r
+};\r
+\r
+//\r
+// EFI_SERIAL_IO_PROTOCOL instance\r
+//\r
+EFI_SERIAL_IO_PROTOCOL mSerialIo = {\r
+ SERIAL_IO_INTERFACE_REVISION,\r
+ SerialReset,\r
+ SerialSetAttributes,\r
+ SerialSetControl,\r
+ SerialGetControl,\r
+ SerialWrite,\r
+ SerialRead,\r
+ &mSerialIoMode\r
+};\r
+\r
+//\r
+// Serial IO Device Path definition\r
+//\r
+typedef struct {\r
+ VENDOR_DEVICE_PATH VendorDevicePath;\r
+ UART_DEVICE_PATH UartDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL EndDevicePath;\r
+} SERIAL_IO_DEVICE_PATH;\r
+\r
+//\r
+// Serial IO Device Patch instance\r
+//\r
+SERIAL_IO_DEVICE_PATH mSerialIoDevicePath = {\r
+ {\r
+ {\r
+ HARDWARE_DEVICE_PATH,\r
+ HW_VENDOR_DP,\r
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),\r
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
+ },\r
+ EFI_DEBUG_AGENT_GUID,\r
+ },\r
+ {\r
+ {\r
+ MESSAGING_DEVICE_PATH,\r
+ MSG_UART_DP,\r
+ (UINT8) (sizeof (UART_DEVICE_PATH)),\r
+ (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)\r
+ },\r
+ 0,\r
+ 0, // BaudRate\r
+ 0, // DataBits\r
+ 0, // Parity\r
+ 0, // StopBits\r
+ },\r
+ {\r
+ END_DEVICE_PATH_TYPE,\r
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+ {\r
+ END_DEVICE_PATH_LENGTH,\r
+ 0\r
+ }\r
+ }\r
+};\r
+\r
+#define DEBGU_SERIAL_IO_FIFO_DEPTH 10\r
+//\r
+// Data buffer for Terminal input character and Debug Symbols.\r
+// The depth is DEBGU_SERIAL_IO_FIFO_DEPTH.\r
+// Fields:\r
+// First UINT8: The index of the first data in array Data[].\r
+// Last UINT8: The index, which you can put a new data into array Data[].\r
+// Surplus UINT8: Identify how many data you can put into array Data[].\r
+// Data[] UINT8: An array, which used to store data.\r
+//\r
+typedef struct {\r
+ UINT8 First;\r
+ UINT8 Last;\r
+ UINT8 Surplus;\r
+ UINT8 Data[DEBGU_SERIAL_IO_FIFO_DEPTH];\r
+} DEBUG_SERIAL_FIFO;\r
+\r
+//\r
+// Global Varibles\r
+//\r
+EFI_HANDLE mSerialIoHandle = NULL;\r
+UINTN mLoopbackBuffer = 0;\r
+DEBUG_SERIAL_FIFO mSerialFifoForTerminal = {0, 0, DEBGU_SERIAL_IO_FIFO_DEPTH, { 0 }};\r
+DEBUG_SERIAL_FIFO mSerialFifoForDebug = {0, 0, DEBGU_SERIAL_IO_FIFO_DEPTH, { 0 }};\r
+\r
+/**\r
+ Detect whether specific FIFO is empty or not.\r
+ \r
+ @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.\r
+\r
+ @return whether specific FIFO is empty or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsDebugTermianlFifoEmpty (\r
+ IN DEBUG_SERIAL_FIFO *Fifo\r
+ )\r
+{\r
+ if (Fifo->Surplus == DEBGU_SERIAL_IO_FIFO_DEPTH) {\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Detect whether specific FIFO is full or not.\r
+\r
+ @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.\r
+\r
+ @return whether specific FIFO is full or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsDebugTerminalFifoFull (\r
+ IN DEBUG_SERIAL_FIFO *Fifo\r
+ )\r
+\r
+{\r
+ if (Fifo->Surplus == 0) {\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Add data to specific FIFO.\r
+\r
+ @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.\r
+ @param[in] Data The data added to FIFO.\r
+\r
+ @retval EFI_SUCCESS Add data to specific FIFO successfully.\r
+ @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full.\r
+\r
+**/\r
+EFI_STATUS\r
+DebugTerminalFifoAdd (\r
+ IN DEBUG_SERIAL_FIFO *Fifo,\r
+ IN UINT8 Data\r
+ )\r
+\r
+{\r
+ //\r
+ // if FIFO full can not add data\r
+ //\r
+ if (IsDebugTerminalFifoFull (Fifo)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // FIFO is not full can add data\r
+ //\r
+ Fifo->Data[Fifo->Last] = Data;\r
+ Fifo->Surplus--;\r
+ Fifo->Last++;\r
+ if (Fifo->Last == DEBGU_SERIAL_IO_FIFO_DEPTH) {\r
+ Fifo->Last = 0;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Remove data from specific FIFO.\r
+\r
+ @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.\r
+ @param[out] Data The data removed from FIFO.\r
+\r
+ @retval EFI_SUCCESS Remove data from specific FIFO successfully.\r
+ @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty.\r
+\r
+**/\r
+EFI_STATUS\r
+DebugTerminalFifoRemove (\r
+ IN DEBUG_SERIAL_FIFO *Fifo,\r
+ OUT UINT8 *Data\r
+ )\r
+{\r
+ //\r
+ // if FIFO is empty, no data can remove\r
+ //\r
+ if (IsDebugTermianlFifoEmpty (Fifo)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // FIFO is not empty, can remove data\r
+ //\r
+ *Data = Fifo->Data[Fifo->First];\r
+ Fifo->Surplus++;\r
+ Fifo->First++;\r
+ if (Fifo->First == DEBGU_SERIAL_IO_FIFO_DEPTH) {\r
+ Fifo->First = 0;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Notification function on EFI PCD protocol to install EFI Serial IO protocol based\r
+ on Debug Communication Library. \r
+\r
+ @param[in] Event The event of notify protocol.\r
+ @param[in] Context Notify event context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+InstallSerialIoNotification (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Get Debug Port parameters from PCDs\r
+ //\r
+ mSerialIoDevicePath.UartDevicePath.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);\r
+ mSerialIoDevicePath.UartDevicePath.DataBits = PcdGet8 (PcdUartDefaultDataBits);\r
+ mSerialIoDevicePath.UartDevicePath.Parity = PcdGet8 (PcdUartDefaultParity);\r
+ mSerialIoDevicePath.UartDevicePath.StopBits = PcdGet8 (PcdUartDefaultStopBits);\r
+\r
+ mSerialIoMode.BaudRate = mSerialIoDevicePath.UartDevicePath.BaudRate;\r
+ mSerialIoMode.DataBits = mSerialIoDevicePath.UartDevicePath.DataBits;\r
+ mSerialIoMode.Parity = mSerialIoDevicePath.UartDevicePath.Parity;\r
+ mSerialIoMode.StopBits = mSerialIoDevicePath.UartDevicePath.StopBits;\r
+\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &mSerialIoHandle,\r
+ &gEfiDevicePathProtocolGuid, &mSerialIoDevicePath,\r
+ &gEfiSerialIoProtocolGuid, &mSerialIo,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Debug Agent: Failed to install EFI Serial IO Protocol on Debug Port!\n"));\r
+ }\r
+}\r
+\r
+/**\r
+ Reset serial device.\r
+\r
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
+\r
+ @retval EFI_SUCCESS Reset successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialReset (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This\r
+ )\r
+{\r
+ mSerialIoMode.ControlMask = SERIAL_PORT_DEFAULT_CONTROL_MASK;\r
+ mLoopbackBuffer = 0;\r
+ //\r
+ // Not reset serial devcie hardware indeed.\r
+ //\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Set new attributes to a serial device.\r
+\r
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
+ @param[in] BaudRate The baudrate of the serial device.\r
+ @param[in] ReceiveFifoDepth The depth of receive FIFO buffer.\r
+ @param[in] Timeout The request timeout for a single char.\r
+ @param[in] Parity The type of parity used in serial device.\r
+ @param[in] DataBits Number of databits used in serial device.\r
+ @param[in] StopBits Number of stopbits used in serial device.\r
+\r
+ @retval EFI_SUCCESS The new attributes were set.\r
+ @retval EFI_INVALID_PARAMETER One or more attributes have an unsupported value.\r
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return).\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialSetAttributes (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN UINT64 BaudRate,\r
+ IN UINT32 ReceiveFifoDepth,\r
+ IN UINT32 Timeout,\r
+ IN EFI_PARITY_TYPE Parity,\r
+ IN UINT8 DataBits,\r
+ IN EFI_STOP_BITS_TYPE StopBits\r
+ )\r
+{\r
+ //\r
+ // The Debug Communication Library does not support changing communications parameters, so unless\r
+ // the request is to use the default value or the value the Debug Communication Library is already\r
+ // using, then return EFI_INVALID_PARAMETER.\r
+ //\r
+ if (BaudRate != 0 && BaudRate != PcdGet64 (PcdUartDefaultBaudRate)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (Parity != DefaultParity && Parity != PcdGet8 (PcdUartDefaultParity)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (DataBits != 0 && DataBits != PcdGet8 (PcdUartDefaultDataBits)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (StopBits != DefaultStopBits && StopBits != PcdGet8 (PcdUartDefaultStopBits)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ \r
+ //\r
+ // Update the Timeout value in the mode structure based on the request.\r
+ // The Debug Communication Library can not support a timeout on writes, but the timeout on \r
+ // reads can be provided by this module.\r
+ //\r
+ if (Timeout == 0) {\r
+ mSerialIoMode.Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;\r
+ } else {\r
+ mSerialIoMode.Timeout = Timeout;\r
+ }\r
+ \r
+ //\r
+ // Update the ReceiveFifoDepth value in the mode structure based on the request.\r
+ // This module assumes that the Debug Communication Library uses a FIFO depth of \r
+ // SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH. The Debug Communication Library may actually be \r
+ // using a larger FIFO, but there is no way to tell.\r
+ //\r
+ if (ReceiveFifoDepth == 0 || ReceiveFifoDepth >= SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH) {\r
+ mSerialIoMode.ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Set Control Bits.\r
+\r
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
+ @param[in] Control Control bits that can be settable.\r
+\r
+ @retval EFI_SUCCESS New Control bits were set successfully.\r
+ @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialSetControl (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN UINT32 Control\r
+ )\r
+{\r
+ //\r
+ // The only control bit supported by this module is software loopback.\r
+ // If any other bit is set, then return an error\r
+ //\r
+ if ((Control & (~EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE)) != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ mSerialIoMode.ControlMask = Control;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get ControlBits.\r
+\r
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
+ @param[out] Control Control signals of the serial device.\r
+\r
+ @retval EFI_SUCCESS Get Control signals successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialGetControl (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ OUT UINT32 *Control\r
+ )\r
+{\r
+ DEBUG_PORT_HANDLE Handle;\r
+\r
+ Handle = GetDebugPortHandle ();\r
+ \r
+ //\r
+ // Always assume the output buffer is empty and the Debug Communication Library can process\r
+ // more write requests.\r
+ //\r
+ *Control = mSerialIoMode.ControlMask | EFI_SERIAL_OUTPUT_BUFFER_EMPTY;\r
+ \r
+ //\r
+ // Check to see if the Terminal FIFO is empty and \r
+ // check to see if the input buffer in the Debug Communication Library is empty\r
+ //\r
+ if (!IsDebugTermianlFifoEmpty (&mSerialFifoForTerminal) || DebugPortPollBuffer (Handle)) {\r
+ *Control &= ~EFI_SERIAL_INPUT_BUFFER_EMPTY;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Write the specified number of bytes to serial device.\r
+\r
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
+ @param[in, out] BufferSize On input the size of Buffer, on output the amount of\r
+ data actually written.\r
+ @param[in] Buffer The buffer of data to write.\r
+\r
+ @retval EFI_SUCCESS The data were written successfully.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_TIMEOUT The write operation was stopped due to timeout.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialWrite (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN OUT UINTN *BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ DEBUG_PORT_HANDLE Handle;\r
+\r
+ Handle = GetDebugPortHandle ();\r
+ \r
+ if ((mSerialIoMode.ControlMask & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) != 0) {\r
+ if (*BufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ if ((mLoopbackBuffer & SERIAL_PORT_LOOPBACK_BUFFER_FULL) != 0) {\r
+ *BufferSize = 0;\r
+ return EFI_TIMEOUT;\r
+ }\r
+ mLoopbackBuffer = SERIAL_PORT_LOOPBACK_BUFFER_FULL | *(UINT8 *)Buffer;\r
+ *BufferSize = 1;\r
+ } else {\r
+ *BufferSize = DebugPortWriteBuffer (Handle, Buffer, *BufferSize);\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read the specified number of bytes from serial device.\r
+\r
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
+ @param[in, out] BufferSize On input the size of Buffer, on output the amount of\r
+ data returned in buffer.\r
+ @param[out] Buffer The buffer to return the data into.\r
+\r
+ @retval EFI_SUCCESS The data were read successfully.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_TIMEOUT The read operation was stopped due to timeout.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialRead (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINT8 *Uint8Buffer;\r
+ BOOLEAN OldInterruptState;\r
+ DEBUG_PORT_HANDLE Handle;\r
+ UINT8 Data;\r
+\r
+ Handle = GetDebugPortHandle ();\r
+\r
+ //\r
+ // Save and disable Debug Timer interrupt to avoid it to access Debug Port\r
+ //\r
+ OldInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);\r
+ \r
+ Uint8Buffer = (UINT8 *)Buffer;\r
+ if ((mSerialIoMode.ControlMask & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) != 0) {\r
+ if ((mLoopbackBuffer & SERIAL_PORT_LOOPBACK_BUFFER_FULL) == 0) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+ *Uint8Buffer = (UINT8)(mLoopbackBuffer & 0xff);\r
+ mLoopbackBuffer = 0;\r
+ *BufferSize = 1;\r
+ } else {\r
+ for (Index = 0; Index < *BufferSize; Index++) {\r
+ //\r
+ // Read input character from terminal FIFO firstly\r
+ //\r
+ Status = DebugTerminalFifoRemove (&mSerialFifoForTerminal, &Data);\r
+ if (Status == EFI_SUCCESS) {\r
+ *Uint8Buffer = Data;\r
+ Uint8Buffer ++;\r
+ continue;\r
+ }\r
+ //\r
+ // Read the input character from Debug Port \r
+ //\r
+ if (!DebugPortPollBuffer (Handle)) {\r
+ break;\r
+ }\r
+ DebugPortReadBuffer (Handle, &Data, 1, 0);\r
+\r
+ if (Data== DEBUG_STARTING_SYMBOL_ATTACH ||\r
+ Data == DEBUG_STARTING_SYMBOL_BREAK) {\r
+ //\r
+ // Add the debug symbol into Debug FIFO\r
+ //\r
+ DebugTerminalFifoAdd (&mSerialFifoForDebug, Data);\r
+ } else {\r
+ *Uint8Buffer = Data;\r
+ Uint8Buffer ++;\r
+ }\r
+ }\r
+ *BufferSize = (UINTN)Uint8Buffer - (UINTN)Buffer;\r
+ }\r
+\r
+ //\r
+ // Restore Debug Timer interrupt\r
+ // \r
+ SaveAndSetDebugTimerInterrupt (OldInterruptState);\r
+ \r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read the Attach/Break-in symbols from the debug port.\r
+\r
+ @param[in] Handle Pointer to Debug Port handle.\r
+ @param[out] BreakSymbol Returned break symbol.\r
+\r
+ @retval EFI_SUCCESS Read the symbol in BreakSymbol.\r
+ @retval EFI_NOT_FOUND No read the break symbol.\r
+\r
+**/\r
+EFI_STATUS\r
+DebugReadBreakSymbol (\r
+ IN DEBUG_PORT_HANDLE Handle,\r
+ OUT UINT8 *BreakSymbol\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Data;\r
+\r
+ Status = DebugTerminalFifoRemove (&mSerialFifoForDebug, &Data);\r
+ if (Status != EFI_SUCCESS) {\r
+ if (!DebugPortPollBuffer (Handle)) {\r
+ //\r
+ // No data in Debug Port buffer.\r
+ //\r
+ return EFI_NOT_FOUND;\r
+ } else {\r
+ //\r
+ // Read one character from Debug Port.\r
+ //\r
+ DebugPortReadBuffer (Handle, &Data, 1, 0);\r
+ if ((Data != DEBUG_STARTING_SYMBOL_ATTACH) && (Data != DEBUG_STARTING_SYMBOL_BREAK)) {\r
+ //\r
+ // If the data is not Break symbol, add it into Terminal FIFO\r
+ //\r
+ DebugTerminalFifoAdd (&mSerialFifoForTerminal, Data);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ }\r
+ }\r
+ \r
+ *BreakSymbol = Data;\r
+ return EFI_SUCCESS;\r
+}\r