--- /dev/null
+/** @file\r
+ Serial driver that layers on top of a Serial Port Library instance.\r
+\r
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
+ Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+\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 <Library/UefiBootServicesTableLib.h>\r
+#include <Library/SerialPortLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+#include <Protocol/SerialIo.h>\r
+#include <Protocol/DevicePath.h>\r
+\r
+typedef struct {\r
+ VENDOR_DEVICE_PATH Guid;\r
+ UART_DEVICE_PATH Uart;\r
+ EFI_DEVICE_PATH_PROTOCOL End;\r
+} SERIAL_DEVICE_PATH;\r
+\r
+/**\r
+ Reset the serial device.\r
+\r
+ @param This Protocol instance pointer.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The serial device could not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialReset (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This\r
+ );\r
+\r
+/**\r
+ Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,\r
+ data bits, and stop bits on a serial device.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the\r
+ device's default interface speed.\r
+ @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the\r
+ serial interface. A ReceiveFifoDepth value of 0 will use\r
+ the device's default FIFO depth.\r
+ @param Timeout The requested time out for a single character in microseconds.\r
+ This timeout applies to both the transmit and receive side of the\r
+ interface. A Timeout value of 0 will use the device's default time\r
+ out value.\r
+ @param Parity The type of parity to use on this serial device. A Parity value of\r
+ DefaultParity will use the device's default parity value.\r
+ @param DataBits The number of data bits to use on the serial device. A DataBits\r
+ value of 0 will use the device's default data bit setting.\r
+ @param StopBits The number of stop bits to use on this serial device. A StopBits\r
+ value of DefaultStopBits will use the device's default number of\r
+ stop bits.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The serial device could not be reset.\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 the control bits on a serial device\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Control Set the bits of Control that are settable.\r
+\r
+ @retval EFI_SUCCESS The new control bits were set on the serial device.\r
+ @retval EFI_UNSUPPORTED The serial device does not support this operation.\r
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialSetControl (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN UINT32 Control\r
+ );\r
+\r
+/**\r
+ Retrieves the status of the control bits on a serial device\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Control A pointer to return the current Control signals from the serial device.\r
+\r
+ @retval EFI_SUCCESS The control bits were read from the serial device.\r
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialGetControl (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ OUT UINT32 *Control\r
+ );\r
+\r
+/**\r
+ Writes data to a serial device.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param BufferSize On input, the size of the Buffer. On output, the amount of\r
+ data actually written.\r
+ @param Buffer The buffer of data to write\r
+\r
+ @retval EFI_SUCCESS The data was written.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_TIMEOUT The data write was stopped due to a 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
+ Reads data from a serial device.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param BufferSize On input, the size of the Buffer. On output, the amount of\r
+ data returned in Buffer.\r
+ @param Buffer The buffer to return the data into.\r
+\r
+ @retval EFI_SUCCESS The data was read.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_TIMEOUT The data write was stopped due to a 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_HANDLE mSerialHandle = NULL;\r
+\r
+SERIAL_DEVICE_PATH mSerialDevicePath = {\r
+ {\r
+ { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0} },\r
+ EFI_CALLER_ID_GUID // Use the driver's GUID\r
+ },\r
+ {\r
+ { MESSAGING_DEVICE_PATH, MSG_UART_DP, { sizeof (UART_DEVICE_PATH), 0} },\r
+ 0, // Reserved\r
+ 0, // BaudRate\r
+ 0, // DataBits\r
+ 0, // Parity\r
+ 0 // StopBits\r
+ },\r
+ { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } }\r
+};\r
+\r
+//\r
+// Template used to initialize the Serial IO protocols.\r
+//\r
+EFI_SERIAL_IO_MODE mSerialIoMode = {\r
+ 0, // ControlMask\r
+ 0, // Timeout\r
+ 0, // BaudRate\r
+ 1, // ReceiveFifoDepth\r
+ 0, // DataBits\r
+ 0, // Parity\r
+ 0 // StopBits\r
+};\r
+\r
+EFI_SERIAL_IO_PROTOCOL mSerialIoTemplate = {\r
+ SERIAL_IO_INTERFACE_REVISION,\r
+ SerialReset,\r
+ SerialSetAttributes,\r
+ SerialSetControl,\r
+ SerialGetControl,\r
+ SerialWrite,\r
+ SerialRead,\r
+ &mSerialIoMode\r
+};\r
+\r
+/**\r
+ Reset the serial device.\r
+\r
+ @param This Protocol instance pointer.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The serial device could not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialReset (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_TPL Tpl;\r
+\r
+ Status = SerialPortInitialize ();\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Set the Serial I/O mode and update the device path\r
+ //\r
+\r
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ //\r
+ // Set the Serial I/O mode\r
+ //\r
+ This->Mode->ReceiveFifoDepth = 1;\r
+ This->Mode->Timeout = 0;\r
+ This->Mode->BaudRate = PcdGet64 (PcdUartDefaultBaudRate);\r
+ This->Mode->DataBits = (UINT32) PcdGet8 (PcdUartDefaultDataBits);\r
+ This->Mode->Parity = (UINT32) PcdGet8 (PcdUartDefaultParity);\r
+ This->Mode->StopBits = (UINT32) PcdGet8 (PcdUartDefaultStopBits);\r
+\r
+ //\r
+ // Check if the device path has actually changed\r
+ //\r
+ if (mSerialDevicePath.Uart.BaudRate == This->Mode->BaudRate &&\r
+ mSerialDevicePath.Uart.DataBits == (UINT8) This->Mode->DataBits &&\r
+ mSerialDevicePath.Uart.Parity == (UINT8) This->Mode->Parity &&\r
+ mSerialDevicePath.Uart.StopBits == (UINT8) This->Mode->StopBits\r
+ ) {\r
+ gBS->RestoreTPL (Tpl);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Update the device path\r
+ //\r
+ mSerialDevicePath.Uart.BaudRate = This->Mode->BaudRate;\r
+ mSerialDevicePath.Uart.DataBits = (UINT8) This->Mode->DataBits;\r
+ mSerialDevicePath.Uart.Parity = (UINT8) This->Mode->Parity;\r
+ mSerialDevicePath.Uart.StopBits = (UINT8) This->Mode->StopBits;\r
+\r
+ Status = gBS->ReinstallProtocolInterface (\r
+ mSerialHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ &mSerialDevicePath,\r
+ &mSerialDevicePath\r
+ );\r
+\r
+ gBS->RestoreTPL (Tpl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,\r
+ data bits, and stop bits on a serial device.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the\r
+ device's default interface speed.\r
+ @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the\r
+ serial interface. A ReceiveFifoDepth value of 0 will use\r
+ the device's default FIFO depth.\r
+ @param Timeout The requested time out for a single character in microseconds.\r
+ This timeout applies to both the transmit and receive side of the\r
+ interface. A Timeout value of 0 will use the device's default time\r
+ out value.\r
+ @param Parity The type of parity to use on this serial device. A Parity value of\r
+ DefaultParity will use the device's default parity value.\r
+ @param DataBits The number of data bits to use on the serial device. A DataBits\r
+ value of 0 will use the device's default data bit setting.\r
+ @param StopBits The number of stop bits to use on this serial device. A StopBits\r
+ value of DefaultStopBits will use the device's default number of\r
+ stop bits.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The serial device could not be reset.\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
+ EFI_STATUS Status;\r
+ EFI_TPL Tpl;\r
+\r
+ Status = SerialPortSetAttributes (&BaudRate, &ReceiveFifoDepth, &Timeout, &Parity, &DataBits, &StopBits);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Set the Serial I/O mode and update the device path\r
+ //\r
+\r
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ //\r
+ // Set the Serial I/O mode\r
+ //\r
+ This->Mode->ReceiveFifoDepth = ReceiveFifoDepth;\r
+ This->Mode->Timeout = Timeout;\r
+ This->Mode->BaudRate = BaudRate;\r
+ This->Mode->DataBits = (UINT32) DataBits;\r
+ This->Mode->Parity = (UINT32) Parity;\r
+ This->Mode->StopBits = (UINT32) StopBits;\r
+\r
+ //\r
+ // Check if the device path has actually changed\r
+ //\r
+ if (mSerialDevicePath.Uart.BaudRate == BaudRate &&\r
+ mSerialDevicePath.Uart.DataBits == DataBits &&\r
+ mSerialDevicePath.Uart.Parity == (UINT8) Parity &&\r
+ mSerialDevicePath.Uart.StopBits == (UINT8) StopBits\r
+ ) {\r
+ gBS->RestoreTPL (Tpl);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Update the device path\r
+ //\r
+ mSerialDevicePath.Uart.BaudRate = BaudRate;\r
+ mSerialDevicePath.Uart.DataBits = DataBits;\r
+ mSerialDevicePath.Uart.Parity = (UINT8) Parity;\r
+ mSerialDevicePath.Uart.StopBits = (UINT8) StopBits;\r
+\r
+ Status = gBS->ReinstallProtocolInterface (\r
+ mSerialHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ &mSerialDevicePath,\r
+ &mSerialDevicePath\r
+ );\r
+\r
+ gBS->RestoreTPL (Tpl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set the control bits on a serial device\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Control Set the bits of Control that are settable.\r
+\r
+ @retval EFI_SUCCESS The new control bits were set on the serial device.\r
+ @retval EFI_UNSUPPORTED The serial device does not support this operation.\r
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialSetControl (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN UINT32 Control\r
+ )\r
+{\r
+ return SerialPortSetControl (Control);\r
+}\r
+\r
+/**\r
+ Retrieves the status of the control bits on a serial device\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Control A pointer to return the current Control signals from the serial device.\r
+\r
+ @retval EFI_SUCCESS The control bits were read from the serial device.\r
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialGetControl (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ OUT UINT32 *Control\r
+ )\r
+{\r
+ return SerialPortGetControl (Control);\r
+}\r
+\r
+/**\r
+ Writes data to a serial device.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param BufferSize On input, the size of the Buffer. On output, the amount of\r
+ data actually written.\r
+ @param Buffer The buffer of data to write\r
+\r
+ @retval EFI_SUCCESS The data was written.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_TIMEOUT The data write was stopped due to a 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
+ UINTN Count;\r
+\r
+ Count = SerialPortWrite (Buffer, *BufferSize);\r
+\r
+ if (Count != *BufferSize) {\r
+ *BufferSize = Count;\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Reads data from a serial device.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param BufferSize On input, the size of the Buffer. On output, the amount of\r
+ data returned in Buffer.\r
+ @param Buffer The buffer to return the data into.\r
+\r
+ @retval EFI_SUCCESS The data was read.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_TIMEOUT The data write was stopped due to a 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
+ UINTN Count;\r
+\r
+ Count = 0;\r
+\r
+ if (SerialPortPoll ()) {\r
+ Count = SerialPortRead (Buffer, *BufferSize);\r
+ }\r
+\r
+ if (Count != *BufferSize) {\r
+ *BufferSize = Count;\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Initialization for the Serial Io Protocol.\r
+\r
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
+ @param[in] SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The entry point is executed successfully.\r
+ @retval other Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialDxeInitialize (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = SerialPortInitialize ();\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ mSerialIoMode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);\r
+ mSerialIoMode.DataBits = (UINT32) PcdGet8 (PcdUartDefaultDataBits);\r
+ mSerialIoMode.Parity = (UINT32) PcdGet8 (PcdUartDefaultParity);\r
+ mSerialIoMode.StopBits = (UINT32) PcdGet8 (PcdUartDefaultStopBits);\r
+ mSerialDevicePath.Uart.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);\r
+ mSerialDevicePath.Uart.DataBits = PcdGet8 (PcdUartDefaultDataBits);\r
+ mSerialDevicePath.Uart.Parity = PcdGet8 (PcdUartDefaultParity);\r
+ mSerialDevicePath.Uart.StopBits = PcdGet8 (PcdUartDefaultStopBits);\r
+\r
+ //\r
+ // Make a new handle with Serial IO protocol and its device path on it.\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &mSerialHandle,\r
+ &gEfiSerialIoProtocolGuid, &mSerialIoTemplate,\r
+ &gEfiDevicePathProtocolGuid, &mSerialDevicePath,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r
+\r