From 3ba6a2d18142f80963c1ab9ec27617ba04b04b3f Mon Sep 17 00:00:00 2001 From: Guo Mang Date: Fri, 23 Dec 2016 13:58:51 +0800 Subject: BroxtonPlatformPkg: Add LpssUartSerailDxe Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang --- .../Console/LpssUartSerialDxe/ComponentName.c | 266 +++ .../LpssUartSerialDxe/LpssUartSerailDxe.uni | Bin 0 -> 2056 bytes .../LpssUartSerialDxe/LpssUartSerialDxe.inf | 84 + .../Common/Console/LpssUartSerialDxe/Serial.c | 1811 ++++++++++++++++++++ .../Common/Console/LpssUartSerialDxe/Serial.h | 853 +++++++++ 5 files changed, 3014 insertions(+) create mode 100644 Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/ComponentName.c create mode 100644 Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/LpssUartSerailDxe.uni create mode 100644 Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/LpssUartSerialDxe.inf create mode 100644 Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/Serial.c create mode 100644 Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/Serial.h (limited to 'Platform/BroxtonPlatformPkg') diff --git a/Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/ComponentName.c b/Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/ComponentName.c new file mode 100644 index 0000000000..a685f781de --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/ComponentName.c @@ -0,0 +1,266 @@ +/** @file + UEFI Component Name and Name2 protocol for Isa serial driver. + + Copyright (c) 2006 - 2016, Intel Corporation. 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 "Serial.h" + +#define SERIAL_PORT_NAME "LPSS UART Serial Port # " +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gLpssUartSerialComponentName = { + IsaSerialComponentNameGetDriverName, + IsaSerialComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gLpssUartSerialComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) IsaSerialComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) IsaSerialComponentNameGetControllerName, + "en" +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mLpssUartSerialDriverNameTable[] = { + { + "eng;en", + L"Lpss Uart Serial Driver" + }, + { + NULL, + NULL + } +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param[out] DriverName A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +IsaSerialComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mLpssUartSerialDriverNameTable, + DriverName, + (BOOLEAN) (This == &gLpssUartSerialComponentName) + ); +} + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] ControllerHandle The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param[in] ChildHandle The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param[in] Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param[out] ControllerName A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +IsaSerialComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + SERIAL_DEV *SerialDevice; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + // + // Make sure this driver is currently managing ControllerHandle + // + Status = EfiTestManagedDevice ( + ControllerHandle, + gSerialControllerDriver.DriverBindingHandle, + &gEfiIsaIoProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the Block I/O Protocol on Controller + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSerialIoProtocolGuid, + (VOID **) &SerialIo, + gSerialControllerDriver.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the Serial Controller's Device structure + // + SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo); + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + SerialDevice->ControllerNameTable, + ControllerName, + (BOOLEAN) (This == &gLpssUartSerialComponentName) + ); +} + + +/** + Add the ISO639-2 and RFC4646 component name both for the Serial IO device + + @param[in] SerialDevice A pointer to the SERIAL_DEV instance. + @param[in] IsaIo A pointer to the EFI_ISA_IO_PROTOCOL instance. + +**/ +VOID +AddName ( + IN SERIAL_DEV *SerialDevice, + IN EFI_ISA_IO_PROTOCOL *IsaIo + ) +{ + CHAR16 SerialPortName[sizeof (SERIAL_PORT_NAME)]; + + StrCpyS (SerialPortName, sizeof (SerialPortName) / sizeof (CHAR16), L"LPSS UART Serial Port # "); + SerialPortName[sizeof (SERIAL_PORT_NAME) - 2] = (CHAR16) (L'0' + (UINT8) IsaIo->ResourceList->Device.UID); + AddUnicodeString2 ( + "eng", + gLpssUartSerialComponentName.SupportedLanguages, + &SerialDevice->ControllerNameTable, + (CHAR16 *) SerialPortName, + TRUE + ); + AddUnicodeString2 ( + "en", + gLpssUartSerialComponentName2.SupportedLanguages, + &SerialDevice->ControllerNameTable, + (CHAR16 *) SerialPortName, + FALSE + ); +} + diff --git a/Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/LpssUartSerailDxe.uni b/Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/LpssUartSerailDxe.uni new file mode 100644 index 0000000000..3136ea79b1 Binary files /dev/null and b/Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/LpssUartSerailDxe.uni differ diff --git a/Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/LpssUartSerialDxe.inf b/Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/LpssUartSerialDxe.inf new file mode 100644 index 0000000000..138cf73104 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/LpssUartSerialDxe.inf @@ -0,0 +1,84 @@ +## @file +# Serial driver for standard UARTS on an ISA bus. +# +# Produces the Serial I/O protocol for standard UARTS using ISA I/O. This driver +# supports the 8250, 16450, 16550 and 16550A UART types. +# +# Copyright (c) 2007 - 2016, Intel Corporation. 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = LpssUartSerialDxe + MODULE_UNI_FILE = LpssUartSerialDxe.uni + FILE_GUID = 93B80003-9FB3-11d4-9A3A-0090273FC14D + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeIsaSerial + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# +# DRIVER_BINDING = gSerialControllerDriver +# COMPONENT_NAME = gIsaSerialComponentName +# COMPONENT_NAME2 = gIsaSerialComponentName2 +# + +[Sources] + ComponentName.c + Serial.h + Serial.c + +[Packages] + MdePkg/MdePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec + BroxtonSiPkg/BroxtonSiPkg.dec + +[LibraryClasses] + PcdLib + ReportStatusCodeLib + UefiBootServicesTableLib + MemoryAllocationLib + BaseMemoryLib + DevicePathLib + UefiLib + UefiDriverEntryPoint + DebugLib + PchSerialIoLib + PchSerialIoUartLib + MmPciLib + IoLib + +[Guids] + gEfiUartDevicePathGuid ## SOMETIMES_CONSUMES ## GUID + +[Protocols] + gEfiIsaIoProtocolGuid ## TO_START + gEfiDevicePathProtocolGuid ## TO_START + gEfiSerialIoProtocolGuid ## BY_START + gEfiDevicePathProtocolGuid ## BY_START + +[FeaturePcd] + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdIsaBusSerialUseHalfHandshake|FALSE ## CONSUMES + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate|115200 ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits|8 ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity|1 ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits|1 ## CONSUMES + +[UserExtensions.TianoCore."ExtraFiles"] + IsaSerialDxeExtra.uni + diff --git a/Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/Serial.c b/Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/Serial.c new file mode 100644 index 0000000000..fa6a2667e9 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/Serial.c @@ -0,0 +1,1811 @@ +/** @file + Serial driver for standard UARTS on an ISA bus. + + Copyright (c) 2006 - 2016, Intel Corporation. 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 "Serial.h" + +// +// ISA Serial Driver Global Variables +// +EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = { + SerialControllerDriverSupported, + SerialControllerDriverStart, + SerialControllerDriverStop, + 0xa, + NULL, + NULL +}; + + +SERIAL_DEV gSerialDevTempate = { + SERIAL_DEV_SIGNATURE, + NULL, + { // SerialIo + SERIAL_IO_INTERFACE_REVISION, + IsaSerialReset, + IsaSerialSetAttributes, + IsaSerialSetControl, + IsaSerialGetControl, + IsaSerialWrite, + IsaSerialRead, + NULL + }, + { // SerialMode + SERIAL_PORT_SUPPORT_CONTROL_MASK, + SERIAL_PORT_DEFAULT_TIMEOUT, + 0, + SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH, + 0, + 0, + 0 + }, + NULL, + NULL, + { // UartDevicePath + { + MESSAGING_DEVICE_PATH, + MSG_UART_DP, + { + (UINT8) (sizeof (UART_DEVICE_PATH)), + (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8) + } + }, + 0, + 0, + 0, + 0, + 0 + }, + NULL, + 0, //BaseAddress + { + 0, + 0, + SERIAL_MAX_BUFFER_SIZE, + { 0 } + }, + { + 0, + 0, + SERIAL_MAX_BUFFER_SIZE, + { 0 } + }, + FALSE, + FALSE, + Uart16550A, + NULL +}; + + +/** + Check the device path node whether it's the Flow Control node or not. + + @param[in] FlowControl The device path node to be checked. + + @retval TRUE It's the Flow Control node. + @retval FALSE It's not. + +**/ +BOOLEAN +IsUartFlowControlNode ( + IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl + ) +{ + return (BOOLEAN) ( + (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) && + (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) && + (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid)) + ); +} + + +/** + Check the device path node whether it contains Flow Control node or not. + + @param[in] DevicePath The device path to be checked. + + @retval TRUE It contains the Flow Control node. + @retval FALSE It doesn't. + +**/ +BOOLEAN +ContainsFlowControl ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + while (!IsDevicePathEnd (DevicePath)) { + if (IsUartFlowControlNode ((UART_FLOW_CONTROL_DEVICE_PATH *) DevicePath)) { + return TRUE; + } + DevicePath = NextDevicePathNode (DevicePath); + } + + return FALSE; +} + + +/** + The user Entry Point for module IsaSerial. The user code starts with this function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +InitializeIsaSerial ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Install driver model protocol(s). + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gSerialControllerDriver, + ImageHandle, + &gLpssUartSerialComponentName, + &gLpssUartSerialComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + + +/** + Check to see if this driver supports the given controller + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] Controller The handle of the controller to test. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. + + @retval EFI_SUCCESS This driver can support the given controller. + +**/ +EFI_STATUS +EFIAPI +SerialControllerDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) + +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_ISA_IO_PROTOCOL *IsaIo; + UART_DEVICE_PATH *UartNode; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UART_FLOW_CONTROL_DEVICE_PATH *FlowControlNode; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; + UINTN EntryCount; + UINTN Index; + BOOLEAN HasFlowControl; + + // + // Check RemainingDevicePath validation + // + if (RemainingDevicePath != NULL) { + // + // Check if RemainingDevicePath is the End of Device Path Node, + // if yes, go on checking other conditions + // + if (!IsDevicePathEnd (RemainingDevicePath)) { + // + // If RemainingDevicePath isn't the End of Device Path Node, + // check its validation + // + Status = EFI_UNSUPPORTED; + + UartNode = (UART_DEVICE_PATH *) RemainingDevicePath; + if (UartNode->Header.Type != MESSAGING_DEVICE_PATH || + UartNode->Header.SubType != MSG_UART_DP || + sizeof (UART_DEVICE_PATH) != DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) UartNode) + ) { + goto Error; + } + + if (UartNode->BaudRate > SERIAL_PORT_MAX_BAUD_RATE) { + goto Error; + } + + if (UartNode->Parity < NoParity || UartNode->Parity > SpaceParity) { + goto Error; + } + + if (UartNode->DataBits < 5 || UartNode->DataBits > 8) { + goto Error; + } + + if (UartNode->StopBits < OneStopBit || UartNode->StopBits > TwoStopBits) { + goto Error; + } + + if ((UartNode->DataBits == 5) && (UartNode->StopBits == TwoStopBits)) { + goto Error; + } + + if ((UartNode->DataBits >= 6) && (UartNode->DataBits <= 8) && (UartNode->StopBits == OneFiveStopBits)) { + goto Error; + } + + FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (UartNode); + if (IsUartFlowControlNode (FlowControlNode)) { + // + // If the second node is Flow Control Node, + // return error when it request other than hardware flow control. + // + if ((ReadUnaligned32 (&FlowControlNode->FlowControlMap) & ~UART_FLOW_CONTROL_HARDWARE) != 0) { + goto Error; + } + } + } + } + + // + // Open the IO Abstraction(s) needed to perform the supported test + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiIsaIoProtocolGuid, + (VOID **) &IsaIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (Status == EFI_ALREADY_STARTED) { + if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) { + // + // If RemainingDevicePath is NULL or is the End of Device Path Node + // + return EFI_SUCCESS; + } + // + // When the driver has produced device path with flow control node but RemainingDevicePath only contains UART node, + // return unsupported, and vice versa. + // + Status = gBS->OpenProtocolInformation ( + Controller, + &gEfiIsaIoProtocolGuid, + &OpenInfoBuffer, + &EntryCount + ); + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index = 0; Index < EntryCount; Index ++) { + if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { + Status = gBS->OpenProtocol ( + OpenInfoBuffer[Index].ControllerHandle, + &gEfiDevicePathProtocolGuid, + (VOID **) &DevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + HasFlowControl = ContainsFlowControl (RemainingDevicePath); + if (HasFlowControl ^ ContainsFlowControl (DevicePath)) { + Status = EFI_UNSUPPORTED; + } + } + break; + } + } + FreePool (OpenInfoBuffer); + return Status; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Close the I/O Abstraction(s) used to perform the supported test + // + gBS->CloseProtocol ( + Controller, + &gEfiIsaIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + // + // Open the EFI Device Path protocol needed to perform the supported test + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Use the ISA I/O Protocol to see if Controller is standard ISA UART that + // can be managed by this driver. + // + Status = EFI_SUCCESS; + if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x501)) { + Status = EFI_UNSUPPORTED; + goto Error; + } + +Error: + // + // Close protocol, don't use device path protocol in the Support() function + // + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + + +/** + Start to manage the controller. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] Controller The handle of the controller to test. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. + + @retval EFI_SUCCESS Driver is started successfully. + +**/ +EFI_STATUS +EFIAPI +SerialControllerDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_ISA_IO_PROTOCOL *IsaIo; + SERIAL_DEV *SerialDevice; + UINTN Index; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; + UINTN EntryCount; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + UART_DEVICE_PATH *Uart; + + + SerialDevice = NULL; + // + // Get the Parent Device Path + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { + return Status; + } + // + // Report status code enable the serial + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_P_PC_ENABLE | EFI_PERIPHERAL_SERIAL_PORT, + ParentDevicePath + ); + + // + // Grab the IO abstraction we need to get any work done + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiIsaIoProtocolGuid, + (VOID **) &IsaIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { + goto Error; + } + + if (Status == EFI_ALREADY_STARTED) { + + if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) { + // + // If RemainingDevicePath is NULL or is the End of Device Path Node + // + return EFI_SUCCESS; + } + + // + // Make sure a child handle does not already exist. This driver can only + // produce one child per serial port. + // + Status = gBS->OpenProtocolInformation ( + Controller, + &gEfiIsaIoProtocolGuid, + &OpenInfoBuffer, + &EntryCount + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EFI_ALREADY_STARTED; + for (Index = 0; Index < EntryCount; Index ++) { + if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { + Status = gBS->OpenProtocol ( + OpenInfoBuffer[Index].ControllerHandle, + &gEfiSerialIoProtocolGuid, + (VOID **) &SerialIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + Uart = (UART_DEVICE_PATH *) RemainingDevicePath; + } + break; + } + } + + FreePool (OpenInfoBuffer); + return Status; + } + + if (RemainingDevicePath != NULL) { + if (IsDevicePathEnd (RemainingDevicePath)) { + // + // If RemainingDevicePath is the End of Device Path Node, + // skip enumerate any device and return EFI_SUCESSS + // + return EFI_SUCCESS; + } + } + + // + // Initialize the serial device instance + // + SerialDevice = AllocateCopyPool (sizeof (SERIAL_DEV), &gSerialDevTempate); + if (SerialDevice == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + SerialDevice->SerialIo.Mode = &(SerialDevice->SerialMode); + SerialDevice->IsaIo = IsaIo; + SerialDevice->ParentDevicePath = ParentDevicePath; + + // + // Check if RemainingDevicePath is NULL, + // if yes, use the values from the gSerialDevTempate as no remaining device path was + // passed in. + // + if (RemainingDevicePath != NULL) { + // + // If RemainingDevicePath isn't NULL, + // match the configuration of the RemainingDevicePath. IsHandleSupported() + // already checked to make sure the RemainingDevicePath contains settings + // that we can support. + // + CopyMem (&SerialDevice->UartDevicePath, RemainingDevicePath, sizeof (UART_DEVICE_PATH)); + } + + SerialDevice->HardwareFlowControl = UART_FLOW_CONTROL_HARDWARE; + + // + // Report status code the serial present + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_P_PC_PRESENCE_DETECT | EFI_PERIPHERAL_SERIAL_PORT, + ParentDevicePath + ); + + // + // Build the device path by appending the UART node to the ParentDevicePath. + // The Uart setings are zero here, since SetAttribute() will update them to match + // the default setings. + // + SerialDevice->DevicePath = AppendDevicePathNode ( + ParentDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath + ); + + + // + // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults. + // + SerialDevice->SerialMode.BaudRate = SerialDevice->UartDevicePath.BaudRate; + SerialDevice->SerialMode.DataBits = SerialDevice->UartDevicePath.DataBits; + SerialDevice->SerialMode.Parity = SerialDevice->UartDevicePath.Parity; + SerialDevice->SerialMode.StopBits = SerialDevice->UartDevicePath.StopBits; + + // + // Install protocol interfaces for the serial device. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &SerialDevice->Handle, + &gEfiDevicePathProtocolGuid, + SerialDevice->DevicePath, + &gEfiSerialIoProtocolGuid, + &SerialDevice->SerialIo, + NULL + ); + if (EFI_ERROR (Status)) { + goto Error; + } + // + // Open For Child Device + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiIsaIoProtocolGuid, + (VOID **) &IsaIo, + This->DriverBindingHandle, + SerialDevice->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + +Error: + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->CloseProtocol ( + Controller, + &gEfiIsaIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + if (SerialDevice != NULL) { + if (SerialDevice->DevicePath != NULL) { + gBS->FreePool (SerialDevice->DevicePath); + } + + FreeUnicodeStringTable (SerialDevice->ControllerNameTable); + gBS->FreePool (SerialDevice); + } + } + + return Status; +} + + +/** + Disconnect this driver with the controller, uninstall related protocol instance + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] Controller The handle of the controller to test. + @param[in] NumberOfChildren Number of child device. + @param[in] ChildHandleBuffer A pointer to the remaining portion of a device path. + + @retval EFI_SUCCESS Operation successfully + @retval EFI_DEVICE_ERROR Cannot stop the driver successfully + +**/ +EFI_STATUS +EFIAPI +SerialControllerDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + UINTN Index; + BOOLEAN AllChildrenStopped; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + SERIAL_DEV *SerialDevice; + EFI_ISA_IO_PROTOCOL *IsaIo; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + Status = gBS->HandleProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &DevicePath + ); + + // + // Report the status code disable the serial + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_P_PC_DISABLE | EFI_PERIPHERAL_SERIAL_PORT, + DevicePath + ); + + // + // Complete all outstanding transactions to Controller. + // Don't allow any new transaction to Controller to be started. + // + if (NumberOfChildren == 0) { + // + // Close the bus driver + // + Status = gBS->CloseProtocol ( + Controller, + &gEfiIsaIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + Status = gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + + AllChildrenStopped = TRUE; + + for (Index = 0; Index < NumberOfChildren; Index++) { + + Status = gBS->OpenProtocol ( + ChildHandleBuffer[Index], + &gEfiSerialIoProtocolGuid, + (VOID **) &SerialIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + + SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo); + + Status = gBS->CloseProtocol ( + Controller, + &gEfiIsaIoProtocolGuid, + This->DriverBindingHandle, + ChildHandleBuffer[Index] + ); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + ChildHandleBuffer[Index], + &gEfiDevicePathProtocolGuid, + SerialDevice->DevicePath, + &gEfiSerialIoProtocolGuid, + &SerialDevice->SerialIo, + NULL + ); + if (EFI_ERROR (Status)) { + gBS->OpenProtocol ( + Controller, + &gEfiIsaIoProtocolGuid, + (VOID **) &IsaIo, + This->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + } else { + if (SerialDevice->DevicePath != NULL) { + gBS->FreePool (SerialDevice->DevicePath); + } + + FreeUnicodeStringTable (SerialDevice->ControllerNameTable); + gBS->FreePool (SerialDevice); + } + } + + if (EFI_ERROR (Status)) { + AllChildrenStopped = FALSE; + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + + +/** + Detect whether specific FIFO is full or not. + + @param[in] Fifo A pointer to the Data Structure SERIAL_DEV_FIFO. + + @return whether specific FIFO is full or not. + +**/ +BOOLEAN +IsaSerialFifoFull ( + IN SERIAL_DEV_FIFO *Fifo + ) +{ + if (Fifo->Surplus == 0) { + return TRUE; + } + + return FALSE; +} + + +/** + Detect whether specific FIFO is empty or not. + + @param[in] Fifo A pointer to the Data Structure SERIAL_DEV_FIFO. + + @return whether specific FIFO is empty or not. + +**/ +BOOLEAN +IsaSerialFifoEmpty ( + IN SERIAL_DEV_FIFO *Fifo + ) +{ + if (Fifo->Surplus == SERIAL_MAX_BUFFER_SIZE) { + return TRUE; + } + + return FALSE; +} + + +/** + Add data to specific FIFO. + + @param[in] Fifo A pointer to the Data Structure SERIAL_DEV_FIFO + @param[in] Data the data added to FIFO + + @retval EFI_SUCCESS Add data to specific FIFO successfully + @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full + +**/ +EFI_STATUS +IsaSerialFifoAdd ( + IN SERIAL_DEV_FIFO *Fifo, + IN UINT8 Data + ) +{ + // + // if FIFO full can not add data + // + if (IsaSerialFifoFull (Fifo)) { + return EFI_OUT_OF_RESOURCES; + } + // + // FIFO is not full can add data + // + Fifo->Data[Fifo->Last] = Data; + Fifo->Surplus--; + Fifo->Last++; + if (Fifo->Last == SERIAL_MAX_BUFFER_SIZE) { + Fifo->Last = 0; + } + + return EFI_SUCCESS; +} + + +/** + Remove data from specific FIFO. + + @param[in] Fifo A pointer to the Data Structure SERIAL_DEV_FIFO + @param[in] Data the data removed from FIFO + + @retval EFI_SUCCESS Remove data from specific FIFO successfully + @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty + +**/ +EFI_STATUS +IsaSerialFifoRemove ( + IN SERIAL_DEV_FIFO *Fifo, + OUT UINT8 *Data + ) +{ + // + // if FIFO is empty, no data can remove + // + if (IsaSerialFifoEmpty (Fifo)) { + return EFI_OUT_OF_RESOURCES; + } + // + // FIFO is not empty, can remove data + // + *Data = Fifo->Data[Fifo->First]; + Fifo->Surplus++; + Fifo->First++; + if (Fifo->First == SERIAL_MAX_BUFFER_SIZE) { + Fifo->First = 0; + } + + return EFI_SUCCESS; +} + + +/** + Reads and writes all avaliable data. + + @param[in] SerialDevice The device to flush + + @retval EFI_SUCCESS Data was read/written successfully. + @retval EFI_OUT_OF_RESOURCE Failed because software receive FIFO is full. Note, when + this happens, pending writes are not done. + +**/ +EFI_STATUS +IsaSerialReceiveTransmit ( + IN SERIAL_DEV *SerialDevice + ) +{ + SERIAL_PORT_LSR Lsr; + UINT8 Data; + BOOLEAN ReceiveFifoFull; + SERIAL_PORT_MSR Msr; + SERIAL_PORT_MCR Mcr; + UINTN TimeOut; + + Data = 0; + + // + // Begin the read or write + // + if (SerialDevice->SoftwareLoopbackEnable) { + do { + ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive); + if (!IsaSerialFifoEmpty (&SerialDevice->Transmit)) { + IsaSerialFifoRemove (&SerialDevice->Transmit, &Data); + if (ReceiveFifoFull) { + return EFI_OUT_OF_RESOURCES; + } + + IsaSerialFifoAdd (&SerialDevice->Receive, Data); + } + } while (!IsaSerialFifoEmpty (&SerialDevice->Transmit)); + } else { + ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive); + // + // For full handshake flow control, tell the peer to send data + // if receive buffer is available. + // + if (SerialDevice->HardwareFlowControl && + !FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)&& + !ReceiveFifoFull + ) { + Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); + Mcr.Bits.Rts = 1; + WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); + } + do { + Lsr.Data = READ_LSR (SerialDevice->IsaIo, SerialDevice->BaseAddress); + + // + // Flush incomming data to prevent a an overrun during a long write + // + if ((Lsr.Bits.Dr == 1) && !ReceiveFifoFull) { + ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive); + if (!ReceiveFifoFull) { + if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Oe == 1 || Lsr.Bits.Pe == 1 || Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) { + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE, + EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT, + SerialDevice->DevicePath + ); + if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Pe == 1|| Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) { + Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress); + continue; + } + } + + Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress); + + IsaSerialFifoAdd (&SerialDevice->Receive, Data); + + // + // For full handshake flow control, if receive buffer full + // tell the peer to stop sending data. + // + if (SerialDevice->HardwareFlowControl && + !FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake) && + IsaSerialFifoFull (&SerialDevice->Receive) + ) { + Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); + Mcr.Bits.Rts = 0; + WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); + } + + + continue; + } else { + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER | EFI_PERIPHERAL_SERIAL_PORT, + SerialDevice->DevicePath + ); + } + } + // + // Do the write + // + if (Lsr.Bits.Thre == 1 && !IsaSerialFifoEmpty (&SerialDevice->Transmit)) { + // + // Make sure the transmit data will not be missed + // + if (SerialDevice->HardwareFlowControl) { + // + // For half handshake flow control assert RTS before sending. + // + if (FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)) { + Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); + Mcr.Bits.Rts= 0; + WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); + } + // + // Wait for CTS + // + TimeOut = 0; + Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress); + while ((Msr.Bits.Dcd == 1) && ((Msr.Bits.Cts == 0) ^ FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake))) { + gBS->Stall (TIMEOUT_STALL_INTERVAL); + TimeOut++; + if (TimeOut > 5) { + break; + } + + Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress); + } + + if ((Msr.Bits.Dcd == 0) || ((Msr.Bits.Cts == 1) ^ FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake))) { + IsaSerialFifoRemove (&SerialDevice->Transmit, &Data); + WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data); + } + + // + // For half handshake flow control, tell DCE we are done. + // + if (FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)) { + Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); + Mcr.Bits.Rts = 1; + WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); + } + } else { + IsaSerialFifoRemove (&SerialDevice->Transmit, &Data); + WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data); + } + } + } while (Lsr.Bits.Thre == 1 && !IsaSerialFifoEmpty (&SerialDevice->Transmit)); + } + + return EFI_SUCCESS; +} + + +/** + Reset serial device. + + @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL + + @retval EFI_SUCCESS Reset successfully + @retval EFI_DEVICE_ERROR Failed to reset + +**/ +EFI_STATUS +EFIAPI +IsaSerialReset ( + IN EFI_SERIAL_IO_PROTOCOL *This + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + SERIAL_DEV *SerialDevice; + SERIAL_PORT_LCR Lcr; + SERIAL_PORT_IER Ier; + SERIAL_PORT_MCR Mcr; + SERIAL_PORT_FCR Fcr; + EFI_TPL Tpl; + UINT32 Control; + + SerialDevice = SERIAL_DEV_FROM_THIS (This); + + // + // Report the status code reset the serial + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_P_PC_RESET | EFI_PERIPHERAL_SERIAL_PORT, + SerialDevice->DevicePath + ); + + Tpl = gBS->RaiseTPL (TPL_NOTIFY); + + // + // Make sure DLAB is 0. + // + Lcr.Data = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); + Lcr.Bits.DLab = 0; + WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data); + + // + // Turn off all interrupts + // + Ier.Data = READ_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress); + Ier.Bits.Ravie = 0; + Ier.Bits.Theie = 0; + Ier.Bits.Rie = 0; + Ier.Bits.Mie = 0; + WRITE_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress, Ier.Data); + + // + // Disable the FIFO. + // + Fcr.Bits.TrFIFOE = 0; + WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data); + + // + // Turn off loopback and disable device interrupt. + // + Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); + Mcr.Bits.Out1 = 0; + Mcr.Bits.Out2 = 0; + Mcr.Bits.Lme = 0; + WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); + + // + // Clear the scratch pad register + // + WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0); + + + if (EFI_ERROR (Status)) { + gBS->RestoreTPL (Tpl); + return EFI_DEVICE_ERROR; + } + // + // Go set the current control bits + // + Control = 0; + if (SerialDevice->HardwareFlowControl) { + Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE; + } + if (SerialDevice->SoftwareLoopbackEnable) { + Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE; + } + // + // for 16550A enable FIFO, 16550 disable FIFO + // + Fcr.Bits.TrFIFOE = 1; + Fcr.Bits.ResetRF = 1; + Fcr.Bits.ResetTF = 1; + WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data); + + // + // Reset the software FIFO + // + SerialDevice->Receive.First = 0; + SerialDevice->Receive.Last = 0; + SerialDevice->Receive.Surplus = SERIAL_MAX_BUFFER_SIZE; + SerialDevice->Transmit.First = 0; + SerialDevice->Transmit.Last = 0; + SerialDevice->Transmit.Surplus = SERIAL_MAX_BUFFER_SIZE; + + gBS->RestoreTPL (Tpl); + + // + // Device reset is complete + // + return EFI_SUCCESS; +} + + +/** + Set new attributes to a serial device. + + @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL + @param[in] BaudRate The baudrate of the serial device + @param[in] ReceiveFifoDepth The depth of receive FIFO buffer + @param[in] Timeout The request timeout for a single char + @param[in] Parity The type of parity used in serial device + @param[in] DataBits Number of databits used in serial device + @param[in] StopBits Number of stopbits used in serial device + + @retval EFI_SUCCESS The new attributes were set + @retval EFI_INVALID_PARAMETERS One or more attributes have an unsupported value + @retval EFI_UNSUPPORTED Data Bits can not set to 5 or 6 + @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return) + +**/ +EFI_STATUS +EFIAPI +IsaSerialSetAttributes ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT64 BaudRate, + IN UINT32 ReceiveFifoDepth, + IN UINT32 Timeout, + IN EFI_PARITY_TYPE Parity, + IN UINT8 DataBits, + IN EFI_STOP_BITS_TYPE StopBits + ) +{ + EFI_STATUS Status; + SERIAL_DEV *SerialDevice; + UINT32 Divisor; + UINT32 Remained; + SERIAL_PORT_LCR Lcr; + UART_DEVICE_PATH *Uart; + EFI_TPL Tpl; + + SerialDevice = SERIAL_DEV_FROM_THIS (This); + + // + // Check for default settings and fill in actual values. + // + if (BaudRate == 0) { + BaudRate = PcdGet64 (PcdUartDefaultBaudRate); + } + + if (ReceiveFifoDepth == 0) { + ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH; + } + + if (Timeout == 0) { + Timeout = SERIAL_PORT_DEFAULT_TIMEOUT; + } + + if (Parity == DefaultParity) { + Parity = (EFI_PARITY_TYPE) PcdGet8 (PcdUartDefaultParity); + } + + if (DataBits == 0) { + DataBits = PcdGet8 (PcdUartDefaultDataBits); + } + + if (StopBits == DefaultStopBits) { + StopBits = (EFI_STOP_BITS_TYPE) PcdGet8 (PcdUartDefaultStopBits); + } + // + // 5 and 6 data bits can not be verified on a 16550A UART + // Return EFI_INVALID_PARAMETER if an attempt is made to use these settings. + // + if ((DataBits == 5) || (DataBits == 6)) { + return EFI_INVALID_PARAMETER; + } + // + // Make sure all parameters are valid + // + if ((BaudRate > SERIAL_PORT_MAX_BAUD_RATE) || (BaudRate < SERIAL_PORT_MIN_BAUD_RATE)) { + return EFI_INVALID_PARAMETER; + } + + if (BaudRate < 75) { + BaudRate = 50; + } else if (BaudRate < 110) { + BaudRate = 75; + } else if (BaudRate < 134) { + BaudRate = 110; + } else if (BaudRate < 150) { + BaudRate = 134; + } else if (BaudRate < 300) { + BaudRate = 150; + } else if (BaudRate < 600) { + BaudRate = 300; + } else if (BaudRate < 1200) { + BaudRate = 600; + } else if (BaudRate < 1800) { + BaudRate = 1200; + } else if (BaudRate < 2000) { + BaudRate = 1800; + } else if (BaudRate < 2400) { + BaudRate = 2000; + } else if (BaudRate < 3600) { + BaudRate = 2400; + } else if (BaudRate < 4800) { + BaudRate = 3600; + } else if (BaudRate < 7200) { + BaudRate = 4800; + } else if (BaudRate < 9600) { + BaudRate = 7200; + } else if (BaudRate < 19200) { + BaudRate = 9600; + } else if (BaudRate < 38400) { + BaudRate = 19200; + } else if (BaudRate < 57600) { + BaudRate = 38400; + } else if (BaudRate < 115200) { + BaudRate = 57600; + } else if (BaudRate <= SERIAL_PORT_MAX_BAUD_RATE) { + BaudRate = 115200; + } + + if ((ReceiveFifoDepth < 1) || (ReceiveFifoDepth > SERIAL_PORT_MAX_RECEIVE_FIFO_DEPTH)) { + return EFI_INVALID_PARAMETER; + } + + if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) { + return EFI_INVALID_PARAMETER; + } + + if ((Parity < NoParity) || (Parity > SpaceParity)) { + return EFI_INVALID_PARAMETER; + } + + if ((DataBits < 5) || (DataBits > 8)) { + return EFI_INVALID_PARAMETER; + } + + if ((StopBits < OneStopBit) || (StopBits > TwoStopBits)) { + return EFI_INVALID_PARAMETER; + } + + // + // for DataBits = 6,7,8, StopBits can not set OneFiveStopBits + // + if ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits)) { + return EFI_INVALID_PARAMETER; + } + + // + // Compute divisor use to program the baud rate using a round determination + // + Divisor = (UINT32) DivU64x32Remainder ( + SERIAL_PORT_INPUT_CLOCK, + ((UINT32) BaudRate * 16), + &Remained + ); + if (Remained != 0) { + Divisor += 1; + } + + if ((Divisor == 0) || ((Divisor & 0xffff0000) != 0)) { + return EFI_INVALID_PARAMETER; + } + + Tpl = gBS->RaiseTPL (TPL_NOTIFY); + + // + // Compute the actual baud rate that the serial port will be programmed for. + // + BaudRate = SERIAL_PORT_INPUT_CLOCK / Divisor / 16; + + // + // Put serial port on Divisor Latch Mode + // + Lcr.Data = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); + Lcr.Bits.DLab = 1; + WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data); + + // + // Write the divisor to the serial port + // + WRITE_DLL (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) (Divisor & 0xff)); + WRITE_DLM (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) ((Divisor >> 8) & 0xff)); + + // + // Put serial port back in normal mode and set remaining attributes. + // + Lcr.Bits.DLab = 0; + + switch (Parity) { + case NoParity: + Lcr.Bits.ParEn = 0; + Lcr.Bits.EvenPar = 0; + Lcr.Bits.SticPar = 0; + break; + + case EvenParity: + Lcr.Bits.ParEn = 1; + Lcr.Bits.EvenPar = 1; + Lcr.Bits.SticPar = 0; + break; + + case OddParity: + Lcr.Bits.ParEn = 1; + Lcr.Bits.EvenPar = 0; + Lcr.Bits.SticPar = 0; + break; + + case SpaceParity: + Lcr.Bits.ParEn = 1; + Lcr.Bits.EvenPar = 1; + Lcr.Bits.SticPar = 1; + break; + + case MarkParity: + Lcr.Bits.ParEn = 1; + Lcr.Bits.EvenPar = 0; + Lcr.Bits.SticPar = 1; + break; + + default: + break; + } + + switch (StopBits) { + case OneStopBit: + Lcr.Bits.StopB = 0; + break; + + case OneFiveStopBits: + case TwoStopBits: + Lcr.Bits.StopB = 1; + break; + + default: + break; + } + + // + // DataBits + // + Lcr.Bits.SerialDB = (UINT8) ((DataBits - 5) & 0x03); + WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data); + + // + // Set the Serial I/O mode + // + This->Mode->BaudRate = BaudRate; + This->Mode->ReceiveFifoDepth = ReceiveFifoDepth; + This->Mode->Timeout = Timeout; + This->Mode->Parity = Parity; + This->Mode->DataBits = DataBits; + This->Mode->StopBits = StopBits; + + // + // See if Device Path Node has actually changed + // + if (SerialDevice->UartDevicePath.BaudRate == BaudRate && + SerialDevice->UartDevicePath.DataBits == DataBits && + SerialDevice->UartDevicePath.Parity == Parity && + SerialDevice->UartDevicePath.StopBits == StopBits + ) { + gBS->RestoreTPL (Tpl); + return EFI_SUCCESS; + } + + // + // Update the device path + // + SerialDevice->UartDevicePath.BaudRate = BaudRate; + SerialDevice->UartDevicePath.DataBits = DataBits; + SerialDevice->UartDevicePath.Parity = (UINT8) Parity; + SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits; + + Status = EFI_SUCCESS; + if (SerialDevice->Handle != NULL) { + Uart = (UART_DEVICE_PATH *) ( + (UINTN) SerialDevice->DevicePath + + GetDevicePathSize (SerialDevice->ParentDevicePath) + - END_DEVICE_PATH_LENGTH + ); + CopyMem (Uart, &SerialDevice->UartDevicePath, sizeof (UART_DEVICE_PATH)); + Status = gBS->ReinstallProtocolInterface ( + SerialDevice->Handle, + &gEfiDevicePathProtocolGuid, + SerialDevice->DevicePath, + SerialDevice->DevicePath + ); + } + + gBS->RestoreTPL (Tpl); + + return Status; +} + + +/** + Set Control Bits. + + @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL + @param[in] Control Control bits that can be settable + + @retval EFI_SUCCESS New Control bits were set successfully + @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported + +**/ +EFI_STATUS +EFIAPI +IsaSerialSetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT32 Control + ) +{ + SERIAL_DEV *SerialDevice; + SERIAL_PORT_MCR Mcr; + EFI_TPL Tpl; + UART_FLOW_CONTROL_DEVICE_PATH *FlowControl; + EFI_STATUS Status; + + // + // The control bits that can be set are : + // EFI_SERIAL_DATA_TERMINAL_READY: 0x0001 // WO + // EFI_SERIAL_REQUEST_TO_SEND: 0x0002 // WO + // EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000 // RW + // EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000 // RW + // EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE: 0x4000 // RW + // + SerialDevice = SERIAL_DEV_FROM_THIS (This); + + // + // first determine the parameter is invalid + // + if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY | + EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE | + EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0) { + return EFI_UNSUPPORTED; + } + + Tpl = gBS->RaiseTPL (TPL_NOTIFY); + + Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); + Mcr.Bits.DtrC = 0; + Mcr.Bits.Rts = 0; + Mcr.Bits.Lme = 0; + SerialDevice->SoftwareLoopbackEnable = FALSE; + SerialDevice->HardwareFlowControl = FALSE; + + if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) { + Mcr.Bits.DtrC = 1; + } + + if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) { + Mcr.Bits.Rts = 1; + } + + if ((Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) == EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) { + Mcr.Bits.Lme = 1; + } + + if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) == EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) { + SerialDevice->HardwareFlowControl = TRUE; + } + + WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); + + if ((Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) == EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) { + SerialDevice->SoftwareLoopbackEnable = TRUE; + } + + Status = EFI_SUCCESS; + if (SerialDevice->Handle != NULL) { + FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) ( + (UINTN) SerialDevice->DevicePath + + GetDevicePathSize (SerialDevice->ParentDevicePath) + - END_DEVICE_PATH_LENGTH + + sizeof (UART_DEVICE_PATH) + ); + if (IsUartFlowControlNode (FlowControl) && + ((ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) ^ SerialDevice->HardwareFlowControl)) { + // + // Flow Control setting is changed, need to reinstall device path protocol + // + WriteUnaligned32 (&FlowControl->FlowControlMap, SerialDevice->HardwareFlowControl ? UART_FLOW_CONTROL_HARDWARE : 0); + Status = gBS->ReinstallProtocolInterface ( + SerialDevice->Handle, + &gEfiDevicePathProtocolGuid, + SerialDevice->DevicePath, + SerialDevice->DevicePath + ); + } + } + + gBS->RestoreTPL (Tpl); + + return Status; +} + + +/** + Get Control Bits. + + @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL + @param[out] Control Control signals of the serial device + + @retval EFI_SUCCESS Get Control signals successfully + +**/ +EFI_STATUS +EFIAPI +IsaSerialGetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + OUT UINT32 *Control + ) +{ + SERIAL_DEV *SerialDevice; + SERIAL_PORT_MSR Msr; + SERIAL_PORT_MCR Mcr; + EFI_TPL Tpl; + + Tpl = gBS->RaiseTPL (TPL_NOTIFY); + + SerialDevice = SERIAL_DEV_FROM_THIS (This); + + *Control = 0; + + // + // Read the Modem Status Register + // + Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress); + + if (Msr.Bits.Cts == 1) { + *Control |= EFI_SERIAL_CLEAR_TO_SEND; + } + + if (Msr.Bits.Dsr == 1) { + *Control |= EFI_SERIAL_DATA_SET_READY; + } + + if (Msr.Bits.Ri == 1) { + *Control |= EFI_SERIAL_RING_INDICATE; + } + + if (Msr.Bits.Dcd == 1) { + *Control |= EFI_SERIAL_CARRIER_DETECT; + } + // + // Read the Modem Control Register + // + Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); + + if (Mcr.Bits.DtrC == 1) { + *Control |= EFI_SERIAL_DATA_TERMINAL_READY; + } + + if (Mcr.Bits.Rts == 1) { + *Control |= EFI_SERIAL_REQUEST_TO_SEND; + } + + if (Mcr.Bits.Lme == 1) { + *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE; + } + + if (SerialDevice->HardwareFlowControl) { + *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE; + } + // + // See if the Transmit FIFO is empty + // + IsaSerialReceiveTransmit (SerialDevice); + + if (IsaSerialFifoEmpty (&SerialDevice->Transmit)) { + *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY; + } + // + // See if the Receive FIFO is empty. + // + IsaSerialReceiveTransmit (SerialDevice); + + if (IsaSerialFifoEmpty (&SerialDevice->Receive)) { + *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY; + } + + if (SerialDevice->SoftwareLoopbackEnable) { + *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE; + } + + gBS->RestoreTPL (Tpl); + + return EFI_SUCCESS; +} + + +/** + Write the specified number of bytes to serial device. + + @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL + @param[in, out] BufferSize On input the size of Buffer, on output the amount of + data actually written + @param[in] Buffer The buffer of data to write + + @retval EFI_SUCCESS The data were written successfully + @retval EFI_DEVICE_ERROR The device reported an error + @retval EFI_TIMEOUT The write operation was stopped due to timeout + +**/ +EFI_STATUS +EFIAPI +IsaSerialWrite ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + UINT8 *CharBuffer; + EFI_TPL Tpl; + + if (*BufferSize == 0) { + return EFI_SUCCESS; + } + + if (Buffer == NULL) { + return EFI_DEVICE_ERROR; + } + + Tpl = gBS->RaiseTPL (TPL_NOTIFY); + + CharBuffer = (UINT8 *) Buffer; + + PchSerialIoUartOut (Uart2, CharBuffer, *BufferSize); + + gBS->RestoreTPL (Tpl); + + return EFI_SUCCESS; +} + + +/** + Read the specified number of bytes from serial device. + + @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL + @param[in, out] BufferSize On input the size of Buffer, on output the amount of + data returned in buffer + @param[out] Buffer The buffer to return the data into + + @retval EFI_SUCCESS The data were read successfully + @retval EFI_DEVICE_ERROR The device reported an error + @retval EFI_TIMEOUT The read operation was stopped due to timeout + +**/ +EFI_STATUS +EFIAPI +IsaSerialRead ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + SERIAL_DEV *SerialDevice; + EFI_TPL Tpl; + + SerialDevice = SERIAL_DEV_FROM_THIS (This); + + if (*BufferSize == 0) { + return EFI_SUCCESS; + } + + if (Buffer == NULL) { + return EFI_DEVICE_ERROR; + } + + Tpl = gBS->RaiseTPL (TPL_NOTIFY); + + *BufferSize = PchSerialIoUartIn(Uart2, Buffer, *BufferSize, FALSE); + + gBS->RestoreTPL (Tpl); + + return EFI_SUCCESS; +} + + +/** + Use scratchpad register to test if this serial port is present. + + @param[in] SerialDevice Pointer to serial device structure + + @return if this serial port is present + +**/ +BOOLEAN +IsaSerialPortPresent ( + IN SERIAL_DEV *SerialDevice + ) +{ + UINT8 Temp; + BOOLEAN Status; + + Status = TRUE; + + // + // Save SCR reg + // + Temp = READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); + WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0xAA); + + if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0xAA) { + Status = FALSE; + } + + WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0x55); + + if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0x55) { + Status = FALSE; + } + // + // Restore SCR + // + WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Temp); + + return Status; +} + + +/** + Use IsaIo protocol to read serial port. + + @param[in] IsaIo Pointer to EFI_ISA_IO_PROTOCOL instance + @param[in] BaseAddress Serial port register group base address + @param[in] Offset Offset in register group + + @return Data read from serial port + +**/ +UINT8 +IsaSerialReadPort ( + IN EFI_ISA_IO_PROTOCOL *IsaIo, + IN UINT16 BaseAddress, + IN UINT32 Offset + ) +{ + UINT8 Data; + + // + // Use IsaIo to access IO + // + IsaIo->Io.Read ( + IsaIo, + EfiIsaIoWidthUint8, + BaseAddress + Offset, + 1, + &Data + ); + + return Data; +} + + +/** + Use IsaIo protocol to write serial port. + + @param[in] IsaIo Pointer to EFI_ISA_IO_PROTOCOL instance + @param[in] BaseAddress Serial port register group base address + @param[in] Offset Offset in register group + @param[in] Data data which is to be written to some serial port register + +**/ +VOID +IsaSerialWritePort ( + IN EFI_ISA_IO_PROTOCOL *IsaIo, + IN UINT16 BaseAddress, + IN UINT32 Offset, + IN UINT8 Data + ) +{ + // + // Use IsaIo to access IO + // + IsaIo->Io.Write ( + IsaIo, + EfiIsaIoWidthUint8, + BaseAddress + Offset, + 1, + &Data + ); +} + diff --git a/Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/Serial.h b/Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/Serial.h new file mode 100644 index 0000000000..5be600e0d2 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Console/LpssUartSerialDxe/Serial.h @@ -0,0 +1,853 @@ +/** @file + Include for Serial Driver + + Copyright (c) 2006 - 2016, Intel Corporation. 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. + +**/ + +#ifndef _SERIAL_H_ +#define _SERIAL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Driver Binding Externs +// +extern EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver; +extern EFI_COMPONENT_NAME_PROTOCOL gLpssUartSerialComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gLpssUartSerialComponentName2; + +// +// Internal Data Structures +// +#define SERIAL_DEV_SIGNATURE SIGNATURE_32 ('s', 'e', 'r', 'd') +#define SERIAL_MAX_BUFFER_SIZE 16 +#define TIMEOUT_STALL_INTERVAL 10 + +// +// Name: SERIAL_DEV_FIFO +// Purpose: To define Receive FIFO and Transmit FIFO +// Context: Used by serial data transmit and receive +// Fields: +// First UINT32: The index of the first data in array Data[] +// Last UINT32: The index, which you can put a new data into array Data[] +// Surplus UINT32: Identify how many data you can put into array Data[] +// Data[] UINT8 : An array, which used to store data +// +typedef struct { + UINT32 First; + UINT32 Last; + UINT32 Surplus; + UINT8 Data[SERIAL_MAX_BUFFER_SIZE]; +} SERIAL_DEV_FIFO; + +typedef enum { + Uart8250 = 0, + Uart16450 = 1, + Uart16550 = 2, + Uart16550A= 3 +} EFI_UART_TYPE; + +typedef enum { + Uart0 = 0, + Uart1 = 1, + Uart2 = 2, + Uart3 = 3 +} EFI_UART_Number; + +// +// Name: SERIAL_DEV +// Purpose: To provide device specific information +// Context: +// Fields: +// Signature UINTN: The identity of the serial device +// SerialIo SERIAL_IO_PROTOCOL: Serial I/O protocol interface +// SerialMode SERIAL_IO_MODE: +// DevicePath EFI_DEVICE_PATH_PROTOCOL *: Device path of the serial device +// Handle EFI_HANDLE: The handle instance attached to serial device +// BaseAddress UINT16: The base address of specific serial device +// Receive SERIAL_DEV_FIFO: The FIFO used to store data, +// which is received by UART +// Transmit SERIAL_DEV_FIFO: The FIFO used to store data, +// which you want to transmit by UART +// SoftwareLoopbackEnable BOOLEAN: +// Type EFI_UART_TYPE: Specify the UART type of certain serial device +// +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + EFI_SERIAL_IO_PROTOCOL SerialIo; + EFI_SERIAL_IO_MODE SerialMode; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + UART_DEVICE_PATH UartDevicePath; + EFI_ISA_IO_PROTOCOL *IsaIo; + UINT16 BaseAddress; + SERIAL_DEV_FIFO Receive; + SERIAL_DEV_FIFO Transmit; + BOOLEAN SoftwareLoopbackEnable; + BOOLEAN HardwareFlowControl; + EFI_UART_TYPE Type; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; +} SERIAL_DEV; + +#define SERIAL_DEV_FROM_THIS(a) CR (a, SERIAL_DEV, SerialIo, SERIAL_DEV_SIGNATURE) + +// +// Serial Driver Defaults +// +#define SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH 1 +#define SERIAL_PORT_DEFAULT_TIMEOUT 1000000 +#define SERIAL_PORT_SUPPORT_CONTROL_MASK (EFI_SERIAL_CLEAR_TO_SEND | \ + EFI_SERIAL_DATA_SET_READY | \ + EFI_SERIAL_RING_INDICATE | \ + EFI_SERIAL_CARRIER_DETECT | \ + EFI_SERIAL_REQUEST_TO_SEND | \ + EFI_SERIAL_DATA_TERMINAL_READY | \ + EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | \ + EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE | \ + EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE | \ + EFI_SERIAL_OUTPUT_BUFFER_EMPTY | \ + EFI_SERIAL_INPUT_BUFFER_EMPTY) + + +// +// (24000000/13)MHz input clock +// +#define SERIAL_PORT_INPUT_CLOCK 1843200 + +// +// 115200 baud with rounding errors +// +#define SERIAL_PORT_MAX_BAUD_RATE 115400 +#define SERIAL_PORT_MIN_BAUD_RATE 50 + +#define SERIAL_PORT_MAX_RECEIVE_FIFO_DEPTH 16 +#define SERIAL_PORT_MIN_TIMEOUT 1 // 1 uS +#define SERIAL_PORT_MAX_TIMEOUT 100000000 // 100 seconds +// +// UART Registers +// +#define SERIAL_REGISTER_THR 0 // WO Transmit Holding Register +#define SERIAL_REGISTER_RBR 0 // RO Receive Buffer Register +#define SERIAL_REGISTER_DLL 0 // R/W Divisor Latch LSB +#define SERIAL_REGISTER_DLM 1 // R/W Divisor Latch MSB +#define SERIAL_REGISTER_IER 1 // R/W Interrupt Enable Register +#define SERIAL_REGISTER_IIR 2 // RO Interrupt Identification Register +#define SERIAL_REGISTER_FCR 2 // WO FIFO Cotrol Register +#define SERIAL_REGISTER_LCR 3 // R/W Line Control Register +#define SERIAL_REGISTER_MCR 4 // R/W Modem Control Register +#define SERIAL_REGISTER_LSR 5 // R/W Line Status Register +#define SERIAL_REGISTER_MSR 6 // R/W Modem Status Register +#define SERIAL_REGISTER_SCR 7 // R/W Scratch Pad Register +#pragma pack(1) +// +// Name: SERIAL_PORT_IER_BITS +// Purpose: Define each bit in Interrupt Enable Register +// Context: +// Fields: +// Ravie Bit0: Receiver Data Available Interrupt Enable +// Theie Bit1: Transmistter Holding Register Empty Interrupt Enable +// Rie Bit2: Receiver Interrupt Enable +// Mie Bit3: Modem Interrupt Enable +// Reserved Bit4-Bit7: Reserved +// +typedef struct { + UINT8 Ravie : 1; + UINT8 Theie : 1; + UINT8 Rie : 1; + UINT8 Mie : 1; + UINT8 Reserved : 4; +} SERIAL_PORT_IER_BITS; + +// +// Name: SERIAL_PORT_IER +// Purpose: +// Context: +// Fields: +// Bits SERIAL_PORT_IER_BITS: Bits of the IER +// Data UINT8: the value of the IER +// +typedef union { + SERIAL_PORT_IER_BITS Bits; + UINT8 Data; +} SERIAL_PORT_IER; + +// +// Name: SERIAL_PORT_FCR_BITS +// Purpose: Define each bit in FIFO Control Register +// Context: +// Fields: +// TrFIFOE Bit0: Transmit and Receive FIFO Enable +// ResetRF Bit1: Reset Reciever FIFO +// ResetTF Bit2: Reset Transmistter FIFO +// Dms Bit3: DMA Mode Select +// Reserved Bit4-Bit5: Reserved +// Rtb Bit6-Bit7: Receive Trigger Bits +// +typedef struct { + UINT8 TrFIFOE : 1; + UINT8 ResetRF : 1; + UINT8 ResetTF : 1; + UINT8 Dms : 1; + UINT8 Reserved : 2; + UINT8 Rtb : 2; +} SERIAL_PORT_FCR_BITS; + +// +// Name: SERIAL_PORT_FCR +// Purpose: +// Context: +// Fields: +// Bits SERIAL_PORT_FCR_BITS: Bits of the FCR +// Data UINT8: the value of the FCR +// +typedef union { + SERIAL_PORT_FCR_BITS Bits; + UINT8 Data; +} SERIAL_PORT_FCR; + +// +// Name: SERIAL_PORT_LCR_BITS +// Purpose: Define each bit in Line Control Register +// Context: +// Fields: +// SerialDB Bit0-Bit1: Number of Serial Data Bits +// StopB Bit2: Number of Stop Bits +// ParEn Bit3: Parity Enable +// EvenPar Bit4: Even Parity Select +// SticPar Bit5: Sticky Parity +// BrCon Bit6: Break Control +// DLab Bit7: Divisor Latch Access Bit +// +typedef struct { + UINT8 SerialDB : 2; + UINT8 StopB : 1; + UINT8 ParEn : 1; + UINT8 EvenPar : 1; + UINT8 SticPar : 1; + UINT8 BrCon : 1; + UINT8 DLab : 1; +} SERIAL_PORT_LCR_BITS; + +// +// Name: SERIAL_PORT_LCR +// Purpose: +// Context: +// Fields: +// Bits SERIAL_PORT_LCR_BITS: Bits of the LCR +// Data UINT8: the value of the LCR +// +typedef union { + SERIAL_PORT_LCR_BITS Bits; + UINT8 Data; +} SERIAL_PORT_LCR; + +// +// Name: SERIAL_PORT_MCR_BITS +// Purpose: Define each bit in Modem Control Register +// Context: +// Fields: +// DtrC Bit0: Data Terminal Ready Control +// Rts Bit1: Request To Send Control +// Out1 Bit2: Output1 +// Out2 Bit3: Output2, used to disable interrupt +// Lme; Bit4: Loopback Mode Enable +// Reserved Bit5-Bit7: Reserved +// +typedef struct { + UINT8 DtrC : 1; + UINT8 Rts : 1; + UINT8 Out1 : 1; + UINT8 Out2 : 1; + UINT8 Lme : 1; + UINT8 Reserved : 3; +} SERIAL_PORT_MCR_BITS; + +// +// Name: SERIAL_PORT_MCR +// Purpose: +// Context: +// Fields: +// Bits SERIAL_PORT_MCR_BITS: Bits of the MCR +// Data UINT8: the value of the MCR +// +typedef union { + SERIAL_PORT_MCR_BITS Bits; + UINT8 Data; +} SERIAL_PORT_MCR; + +// +// Name: SERIAL_PORT_LSR_BITS +// Purpose: Define each bit in Line Status Register +// Context: +// Fields: +// Dr Bit0: Receiver Data Ready Status +// Oe Bit1: Overrun Error Status +// Pe Bit2: Parity Error Status +// Fe Bit3: Framing Error Status +// Bi Bit4: Break Interrupt Status +// Thre Bit5: Transmistter Holding Register Status +// Temt Bit6: Transmitter Empty Status +// FIFOe Bit7: FIFO Error Status +// +typedef struct { + UINT8 Dr : 1; + UINT8 Oe : 1; + UINT8 Pe : 1; + UINT8 Fe : 1; + UINT8 Bi : 1; + UINT8 Thre : 1; + UINT8 Temt : 1; + UINT8 FIFOe : 1; +} SERIAL_PORT_LSR_BITS; + +// +// Name: SERIAL_PORT_LSR +// Purpose: +// Context: +// Fields: +// Bits SERIAL_PORT_LSR_BITS: Bits of the LSR +// Data UINT8: the value of the LSR +// +typedef union { + SERIAL_PORT_LSR_BITS Bits; + UINT8 Data; +} SERIAL_PORT_LSR; + +// +// Name: SERIAL_PORT_MSR_BITS +// Purpose: Define each bit in Modem Status Register +// Context: +// Fields: +// DeltaCTS Bit0: Delta Clear To Send Status +// DeltaDSR Bit1: Delta Data Set Ready Status +// TrailingEdgeRI Bit2: Trailing Edge of Ring Indicator Status +// DeltaDCD Bit3: Delta Data Carrier Detect Status +// Cts Bit4: Clear To Send Status +// Dsr Bit5: Data Set Ready Status +// Ri Bit6: Ring Indicator Status +// Dcd Bit7: Data Carrier Detect Status +// +typedef struct { + UINT8 DeltaCTS : 1; + UINT8 DeltaDSR : 1; + UINT8 TrailingEdgeRI : 1; + UINT8 DeltaDCD : 1; + UINT8 Cts : 1; + UINT8 Dsr : 1; + UINT8 Ri : 1; + UINT8 Dcd : 1; +} SERIAL_PORT_MSR_BITS; + +// +// Name: SERIAL_PORT_MSR +// Purpose: +// Context: +// Fields: +// Bits SERIAL_PORT_MSR_BITS: Bits of the MSR +// Data UINT8: the value of the MSR +// +typedef union { + SERIAL_PORT_MSR_BITS Bits; + UINT8 Data; +} SERIAL_PORT_MSR; + +#pragma pack() +// +// Define serial register I/O macros +// +#define READ_RBR(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_RBR) +#define READ_DLL(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_DLL) +#define READ_DLM(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_DLM) +#define READ_IER(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_IER) +#define READ_IIR(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_IIR) +#define READ_LCR(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_LCR) +#define READ_MCR(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_MCR) +#define READ_LSR(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_LSR) +#define READ_MSR(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_MSR) +#define READ_SCR(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_SCR) + +#define WRITE_THR(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_THR, D) +#define WRITE_DLL(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_DLL, D) +#define WRITE_DLM(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_DLM, D) +#define WRITE_IER(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_IER, D) +#define WRITE_FCR(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_FCR, D) +#define WRITE_LCR(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_LCR, D) +#define WRITE_MCR(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_MCR, D) +#define WRITE_LSR(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_LSR, D) +#define WRITE_MSR(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_MSR, D) +#define WRITE_SCR(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_SCR, D) + +// +// Prototypes +// Driver model protocol interface +// +/** + Check to see if this driver supports the given controller + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] Controller The handle of the controller to test. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. + + @retval EFI_SUCCESS This driver can support the given controller + +**/ +EFI_STATUS +EFIAPI +SerialControllerDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Start to management the controller passed in + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] Controller The handle of the controller to test. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. + + @retval EFI_SUCCESS Driver is started successfully +**/ +EFI_STATUS +EFIAPI +SerialControllerDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Disconnect this driver with the controller, uninstall related protocol instance + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] Controller The handle of the controller to test. + @param[in] NumberOfChildren Number of child device. + @param[in] ChildHandleBuffer A pointer to the remaining portion of a device path. + + @retval EFI_SUCCESS Operation successfully + @retval EFI_DEVICE_ERROR Cannot stop the driver successfully + +**/ +EFI_STATUS +EFIAPI +SerialControllerDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// Serial I/O Protocol Interface +// +/** + Reset serial device. + + @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL + + @retval EFI_SUCCESS Reset successfully + @retval EFI_DEVICE_ERROR Failed to reset + +**/ +EFI_STATUS +EFIAPI +IsaSerialReset ( + IN EFI_SERIAL_IO_PROTOCOL *This + ); + +/** + Set new attributes to a serial device. + + @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL + @param[in] BaudRate The baudrate of the serial device + @param[in] ReceiveFifoDepth The depth of receive FIFO buffer + @param[in] Timeout The request timeout for a single char + @param[in] Parity The type of parity used in serial device + @param[in] DataBits Number of databits used in serial device + @param[in] StopBits Number of stopbits used in serial device + + @retval EFI_SUCCESS The new attributes were set + @retval EFI_INVALID_PARAMETERS One or more attributes have an unsupported value + @retval EFI_UNSUPPORTED Data Bits can not set to 5 or 6 + @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return) + +**/ +EFI_STATUS +EFIAPI +IsaSerialSetAttributes ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT64 BaudRate, + IN UINT32 ReceiveFifoDepth, + IN UINT32 Timeout, + IN EFI_PARITY_TYPE Parity, + IN UINT8 DataBits, + IN EFI_STOP_BITS_TYPE StopBits + ); + +/** + Set Control Bits. + + @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL + @param[in] Control Control bits that can be settable + + @retval EFI_SUCCESS New Control bits were set successfully + @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported + +**/ +EFI_STATUS +EFIAPI +IsaSerialSetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT32 Control + ); + +/** + Get Control Bits. + + @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL + @param[out] Control Control signals of the serial device + + @retval EFI_SUCCESS Get Control signals successfully + +**/ +EFI_STATUS +EFIAPI +IsaSerialGetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + OUT UINT32 *Control + ); + +/** + Write the specified number of bytes to serial device. + + @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL + @param[in, out] BufferSize On input the size of Buffer, on output the amount of + data actually written + @param[in] Buffer The buffer of data to write + + @retval EFI_SUCCESS The data were written successfully + @retval EFI_DEVICE_ERROR The device reported an error + @retval EFI_TIMEOUT The write operation was stopped due to timeout + +**/ +EFI_STATUS +EFIAPI +IsaSerialWrite ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ); + +/** + Read the specified number of bytes from serial device. + + @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL + @param[in, out] BufferSize On input the size of Buffer, on output the amount of + data returned in buffer + @param[out] Buffer The buffer to return the data into + + @retval EFI_SUCCESS The data were read successfully + @retval EFI_DEVICE_ERROR The device reported an error + @retval EFI_TIMEOUT The read operation was stopped due to timeout + +**/ +EFI_STATUS +EFIAPI +IsaSerialRead ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +// +// Internal Functions +// +/** + Use scratchpad register to test if this serial port is present. + + @param[in] SerialDevice Pointer to serial device structure + + @return if this serial port is present + +**/ +BOOLEAN +IsaSerialPortPresent ( + IN SERIAL_DEV *SerialDevice + ); + +/** + Detect whether specific FIFO is full or not. + + @param[in] Fifo A pointer to the Data Structure SERIAL_DEV_FIFO + + @return whether specific FIFO is full or not + +**/ +BOOLEAN +IsaSerialFifoFull ( + IN SERIAL_DEV_FIFO *Fifo + ); + +/** + Detect whether specific FIFO is empty or not. + + @param[in] Fifo A pointer to the Data Structure SERIAL_DEV_FIFO + + @return whether specific FIFO is empty or not + +**/ +BOOLEAN +IsaSerialFifoEmpty ( + IN SERIAL_DEV_FIFO *Fifo + ); + +/** + Add data to specific FIFO. + + @param[in] Fifo A pointer to the Data Structure SERIAL_DEV_FIFO + @param[in] Data the data added to FIFO + + @retval EFI_SUCCESS Add data to specific FIFO successfully + @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full + +**/ +EFI_STATUS +IsaSerialFifoAdd ( + IN SERIAL_DEV_FIFO *Fifo, + IN UINT8 Data + ); + +/** + Remove data from specific FIFO. + + @param[in] Fifo A pointer to the Data Structure SERIAL_DEV_FIFO + @param[in] Data the data removed from FIFO + + @retval EFI_SUCCESS Remove data from specific FIFO successfully + @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty + +**/ +EFI_STATUS +IsaSerialFifoRemove ( + IN SERIAL_DEV_FIFO *Fifo, + OUT UINT8 *Data + ); + +/** + Reads and writes all avaliable data. + + @param[in] SerialDevice The device to flush + + @retval EFI_SUCCESS Data was read/written successfully. + @retval EFI_OUT_OF_RESOURCE Failed because software receive FIFO is full. Note, when + this happens, pending writes are not done. + +**/ +EFI_STATUS +IsaSerialReceiveTransmit ( + IN SERIAL_DEV *SerialDevice + ); + +/** + Use IsaIo protocol to read serial port. + + @param[in] IsaIo Pointer to EFI_ISA_IO_PROTOCOL instance + @param[in] BaseAddress Serial port register group base address + @param[in] Offset Offset in register group + + @return Data read from serial port + +**/ +UINT8 +IsaSerialReadPort ( + IN EFI_ISA_IO_PROTOCOL *IsaIo, + IN UINT16 BaseAddress, + IN UINT32 Offset + ); + +/** + Use IsaIo protocol to write serial port. + + @param[in] IsaIo Pointer to EFI_ISA_IO_PROTOCOL instance + @param[in] BaseAddress Serial port register group base address + @param[in] Offset Offset in register group + @param[in] Data data which is to be written to some serial port register + +**/ +VOID +IsaSerialWritePort ( + IN EFI_ISA_IO_PROTOCOL *IsaIo, + IN UINT16 BaseAddress, + IN UINT32 Offset, + IN UINT8 Data + ); + +// +// EFI Component Name Functions +// +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param[out] DriverName A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +IsaSerialComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] ControllerHandle The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param[in] ChildHandle The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param[in] Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param[out] ControllerName A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +IsaSerialComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +/** + Add the component name for the serial io device + + @param[in] SerialDevice A pointer to the SERIAL_DEV instance. + @param[in] IsaIo A pointer to the EFI_ISA_IO_PROTOCOL instance. + +**/ +VOID +AddName ( + IN SERIAL_DEV *SerialDevice, + IN EFI_ISA_IO_PROTOCOL *IsaIo + ); + +#endif + -- cgit v1.2.3