--- /dev/null
+/** @file\r
+ UEFI Component Name and Name2 protocol for Isa serial driver.\r
+\r
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Serial.h"\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gPciSioSerialComponentName = {\r
+ SerialComponentNameGetDriverName,\r
+ SerialComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gPciSioSerialComponentName2 = {\r
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SerialComponentNameGetDriverName,\r
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SerialComponentNameGetControllerName,\r
+ "en"\r
+};\r
+\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSerialDriverNameTable[] = {\r
+ {\r
+ "eng;en",\r
+ L"PCI SIO Serial Driver"\r
+ },\r
+ {\r
+ NULL,\r
+ NULL\r
+ }\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 mSioSerialPortName[] = L"SIO Serial Port #%d";\r
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 mPciSerialPortName[] = L"PCI Serial Port #%d";\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+{\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ mSerialDriverNameTable,\r
+ DriverName,\r
+ (BOOLEAN)(This == &gPciSioSerialComponentName)\r
+ );\r
+}\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
+ SERIAL_DEV *SerialDevice;\r
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;\r
+ EFI_GUID *IoProtocolGuid;\r
+\r
+ //\r
+ // Make sure this driver is currently managing ControllerHandle\r
+ //\r
+ IoProtocolGuid = &gEfiSioProtocolGuid;\r
+ Status = EfiTestManagedDevice (\r
+ ControllerHandle,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ IoProtocolGuid\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ IoProtocolGuid = &gEfiPciIoProtocolGuid;\r
+ Status = EfiTestManagedDevice (\r
+ ControllerHandle,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ IoProtocolGuid\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ ControllerNameTable = NULL;\r
+ if (ChildHandle != NULL) {\r
+ Status = EfiTestChildHandle (\r
+ ControllerHandle,\r
+ ChildHandle,\r
+ IoProtocolGuid\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get the Serial I/O Protocol from the child handle\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandle,\r
+ &gEfiSerialIoProtocolGuid,\r
+ (VOID **) &SerialIo,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ ChildHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get the Serial Controller's Device structure\r
+ //\r
+ SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo);\r
+ ControllerNameTable = SerialDevice->ControllerNameTable;\r
+ }\r
+\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ ControllerNameTable,\r
+ ControllerName,\r
+ (BOOLEAN)(This == &gPciSioSerialComponentName)\r
+ );\r
+}\r
+\r
+/**\r
+ Add the ISO639-2 and RFC4646 component name both for the Serial IO device\r
+\r
+ @param SerialDevice A pointer to the SERIAL_DEV instance.\r
+ @param Instance Instance ID for the serial device.\r
+**/\r
+VOID\r
+AddName (\r
+ IN SERIAL_DEV *SerialDevice,\r
+ IN UINT32 Instance\r
+ )\r
+{\r
+ CHAR16 SerialPortName[SERIAL_PORT_NAME_LEN];\r
+ UnicodeSPrint (\r
+ SerialPortName,\r
+ sizeof (SerialPortName),\r
+ (SerialDevice->PciDeviceInfo != NULL) ? PCI_SERIAL_PORT_NAME : SIO_SERIAL_PORT_NAME,\r
+ Instance\r
+ );\r
+ AddUnicodeString2 (\r
+ "eng",\r
+ gPciSioSerialComponentName.SupportedLanguages,\r
+ &SerialDevice->ControllerNameTable,\r
+ SerialPortName,\r
+ TRUE\r
+ );\r
+ AddUnicodeString2 (\r
+ "en",\r
+ gPciSioSerialComponentName2.SupportedLanguages,\r
+ &SerialDevice->ControllerNameTable,\r
+ SerialPortName,\r
+ FALSE\r
+ );\r
+\r
+}\r
--- /dev/null
+## @file\r
+# Serial driver for standard UARTS on a SIO chip or PCI/PCIE card.\r
+#\r
+# Produces the Serial I/O protocol for standard UARTS using Super I/O or PCI I/O.\r
+#\r
+# Copyright (c) 2007 - 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
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = PciSioSerialDxe\r
+ MODULE_UNI_FILE = PciSioSerialDxe.uni\r
+ FILE_GUID = E2775B47-D453-4EE3-ADA7-391A1B05AC17\r
+ MODULE_TYPE = UEFI_DRIVER\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = InitializePciSioSerial\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+# DRIVER_BINDING = gSerialControllerDriver\r
+# COMPONENT_NAME = gPciSioSerialComponentName\r
+# COMPONENT_NAME2 = gPciSioSerialComponentName2\r
+#\r
+\r
+[Sources]\r
+ ComponentName.c\r
+ SerialIo.c\r
+ Serial.h\r
+ Serial.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+ PcdLib\r
+ ReportStatusCodeLib\r
+ UefiBootServicesTableLib\r
+ MemoryAllocationLib\r
+ BaseMemoryLib\r
+ DevicePathLib\r
+ UefiLib\r
+ UefiDriverEntryPoint\r
+ DebugLib\r
+ IoLib\r
+\r
+[Guids]\r
+ gEfiUartDevicePathGuid ## SOMETIMES_CONSUMES ## GUID\r
+\r
+[Protocols]\r
+ gEfiSioProtocolGuid ## TO_START\r
+ gEfiDevicePathProtocolGuid ## TO_START\r
+ gEfiPciIoProtocolGuid ## TO_START\r
+ gEfiSerialIoProtocolGuid ## BY_START\r
+ gEfiDevicePathProtocolGuid ## BY_START\r
+\r
+[FeaturePcd]\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHalfHandshake|FALSE ## CONSUMES\r
+\r
+[Pcd]\r
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate|115200 ## CONSUMES\r
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits|8 ## CONSUMES\r
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity|1 ## CONSUMES\r
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits|1 ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|1843200 ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPciSerialParameters ## CONSUMES\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+ PciSioSerialDxeExtra.uni\r
--- /dev/null
+/** @file\r
+ Serial driver for PCI or SIO UARTS.\r
+\r
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Serial.h"\r
+\r
+//\r
+// ISA Serial Driver Global Variables\r
+//\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = {\r
+ SerialControllerDriverSupported,\r
+ SerialControllerDriverStart,\r
+ SerialControllerDriverStop,\r
+ 0xa,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+CONTROLLER_DEVICE_PATH mControllerDevicePathTemplate = {\r
+ {\r
+ HARDWARE_DEVICE_PATH,\r
+ HW_CONTROLLER_DP,\r
+ sizeof (CONTROLLER_DEVICE_PATH),\r
+ 0\r
+ },\r
+ 0\r
+};\r
+\r
+SERIAL_DEV gSerialDevTemplate = {\r
+ SERIAL_DEV_SIGNATURE,\r
+ NULL,\r
+ {\r
+ SERIAL_IO_INTERFACE_REVISION,\r
+ SerialReset,\r
+ SerialSetAttributes,\r
+ SerialSetControl,\r
+ SerialGetControl,\r
+ SerialWrite,\r
+ SerialRead,\r
+ NULL\r
+ }, // SerialIo\r
+ {\r
+ SERIAL_PORT_SUPPORT_CONTROL_MASK,\r
+ SERIAL_PORT_DEFAULT_TIMEOUT,\r
+ 0,\r
+ 16,\r
+ 0,\r
+ 0,\r
+ 0\r
+ }, // SerialMode\r
+ NULL, // DevicePath\r
+ NULL, // ParentDevicePath\r
+ {\r
+ {\r
+ MESSAGING_DEVICE_PATH,\r
+ MSG_UART_DP,\r
+ {\r
+ (UINT8) (sizeof (UART_DEVICE_PATH)),\r
+ (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)\r
+ }\r
+ },\r
+ 0, 0, 0, 0, 0\r
+ }, // UartDevicePath\r
+ 0, // BaseAddress\r
+ FALSE, // MmioAccess\r
+ 1, // RegisterStride\r
+ 0, // ClockRate\r
+ 16, // ReceiveFifoDepth\r
+ { 0, 0 }, // Receive;\r
+ 16, // TransmitFifoDepth\r
+ { 0, 0 }, // Transmit;\r
+ FALSE, // SoftwareLoopbackEnable;\r
+ FALSE, // HardwareFlowControl;\r
+ NULL, // *ControllerNameTable;\r
+ FALSE, // ContainsControllerNode;\r
+ 0, // Instance;\r
+ NULL // *PciDeviceInfo;\r
+};\r
+\r
+/**\r
+ Check the device path node whether it's the Flow Control node or not.\r
+\r
+ @param[in] FlowControl The device path node to be checked.\r
+ \r
+ @retval TRUE It's the Flow Control node.\r
+ @retval FALSE It's not.\r
+\r
+**/\r
+BOOLEAN\r
+IsUartFlowControlDevicePathNode (\r
+ IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl\r
+ )\r
+{\r
+ return (BOOLEAN) (\r
+ (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) &&\r
+ (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) &&\r
+ (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid))\r
+ );\r
+}\r
+\r
+/**\r
+ The user Entry Point for module PciSioSerial. The user code starts with this function.\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
+InitializePciSioSerial (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Install driver model protocol(s).\r
+ //\r
+ Status = EfiLibInstallDriverBindingComponentName2 (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gSerialControllerDriver,\r
+ ImageHandle,\r
+ &gPciSioSerialComponentName,\r
+ &gPciSioSerialComponentName2\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Initialize UART default setting in gSerialDevTempate\r
+ //\r
+ gSerialDevTemplate.SerialMode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);\r
+ gSerialDevTemplate.SerialMode.DataBits = PcdGet8 (PcdUartDefaultDataBits);\r
+ gSerialDevTemplate.SerialMode.Parity = PcdGet8 (PcdUartDefaultParity);\r
+ gSerialDevTemplate.SerialMode.StopBits = PcdGet8 (PcdUartDefaultStopBits);\r
+ gSerialDevTemplate.UartDevicePath.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);\r
+ gSerialDevTemplate.UartDevicePath.DataBits = PcdGet8 (PcdUartDefaultDataBits);\r
+ gSerialDevTemplate.UartDevicePath.Parity = PcdGet8 (PcdUartDefaultParity);\r
+ gSerialDevTemplate.UartDevicePath.StopBits = PcdGet8 (PcdUartDefaultStopBits);\r
+ gSerialDevTemplate.ClockRate = PcdGet32 (PcdSerialClockRate);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Return whether the controller is a SIO serial controller.\r
+\r
+ @param Controller The controller handle.\r
+\r
+ @retval EFI_SUCCESS The controller is a SIO serial controller.\r
+ @retval others The controller is not a SIO serial controller.\r
+**/\r
+EFI_STATUS\r
+IsSioSerialController (\r
+ EFI_HANDLE Controller\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SIO_PROTOCOL *Sio;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ ACPI_HID_DEVICE_PATH *Acpi;\r
+\r
+ //\r
+ // Open the IO Abstraction(s) needed to perform the supported test\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSioProtocolGuid,\r
+ (VOID **) &Sio,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Close the I/O Abstraction(s) used to perform the supported test\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiSioProtocolGuid,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &DevicePath,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ ASSERT (Status != EFI_ALREADY_STARTED);\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ do {\r
+ Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath;\r
+ DevicePath = NextDevicePathNode (DevicePath);\r
+ } while (!IsDevicePathEnd (DevicePath));\r
+\r
+ if (DevicePathType (Acpi) != ACPI_DEVICE_PATH ||\r
+ (DevicePathSubType (Acpi) != ACPI_DP && DevicePathSubType (Acpi) != ACPI_EXTENDED_DP) ||\r
+ Acpi->HID != EISA_PNP_ID (0x501)\r
+ ) {\r
+ Status = EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Close protocol, don't use device path protocol in the Support() function\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ Controller\r
+ );\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Return whether the controller is a PCI serial controller.\r
+\r
+ @param Controller The controller handle.\r
+\r
+ @retval EFI_SUCCESS The controller is a PCI serial controller.\r
+ @retval others The controller is not a PCI serial controller.\r
+**/\r
+EFI_STATUS\r
+IsPciSerialController (\r
+ EFI_HANDLE Controller\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ PCI_TYPE00 Pci;\r
+ PCI_SERIAL_PARAMETER *PciSerialParameter;\r
+\r
+ //\r
+ // Open the IO Abstraction(s) needed to perform the supported test\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &PciIo,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci);\r
+ if (!EFI_ERROR (Status)) {\r
+ if (!IS_PCI_16550_SERIAL (&Pci)) {\r
+ for (PciSerialParameter = (PCI_SERIAL_PARAMETER *) PcdGetPtr (PcdPciSerialParameters)\r
+ ; PciSerialParameter->VendorId != 0xFFFF\r
+ ; PciSerialParameter++\r
+ ) {\r
+ if ((Pci.Hdr.VendorId == PciSerialParameter->VendorId) &&\r
+ (Pci.Hdr.DeviceId == PciSerialParameter->DeviceId)\r
+ ) {\r
+ break;\r
+ }\r
+ }\r
+ if (PciSerialParameter->VendorId == 0xFFFF) {\r
+ Status = EFI_UNSUPPORTED;\r
+ } else {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Close the I/O Abstraction(s) used to perform the supported test\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ Controller\r
+ );\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Open the EFI Device Path protocol needed to perform the supported test\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &DevicePath,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ ASSERT (Status != EFI_ALREADY_STARTED);\r
+\r
+ //\r
+ // Close protocol, don't use device path protocol in the Support() function\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Check to see if this driver supports the given controller\r
+\r
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param Controller The handle of the controller to test.\r
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.\r
+\r
+ @return EFI_SUCCESS This driver can support the given controller\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialControllerDriverSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+\r
+{\r
+ EFI_STATUS Status;\r
+ UART_DEVICE_PATH *Uart;\r
+ UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;\r
+\r
+ //\r
+ // Test RemainingDevicePath\r
+ //\r
+ if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {\r
+ Status = EFI_UNSUPPORTED;\r
+\r
+ Uart = SkipControllerDevicePathNode (RemainingDevicePath, NULL, NULL);\r
+ if (DevicePathType (Uart) != MESSAGING_DEVICE_PATH ||\r
+ DevicePathSubType (Uart) != MSG_UART_DP ||\r
+ DevicePathNodeLength (Uart) != sizeof (UART_DEVICE_PATH)\r
+ ) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Do a rough check because Clock Rate is unknown until DriverBindingStart()\r
+ //\r
+ if (!VerifyUartParameters (0, Uart->BaudRate, Uart->DataBits, Uart->Parity, Uart->StopBits, NULL, NULL)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);\r
+ if (IsUartFlowControlDevicePathNode (FlowControl)) {\r
+ //\r
+ // If the second node is Flow Control Node,\r
+ // return error when it request other than hardware flow control.\r
+ //\r
+ if ((ReadUnaligned32 (&FlowControl->FlowControlMap) & ~UART_FLOW_CONTROL_HARDWARE) != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+ }\r
+\r
+ Status = IsSioSerialController (Controller);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = IsPciSerialController (Controller);\r
+ }\r
+ return Status; \r
+}\r
+\r
+/**\r
+ Create the child serial device instance.\r
+\r
+ @param Controller The parent controller handle.\r
+ @param Uart Pointer to the UART device path node in RemainingDevicePath,\r
+ or NULL if RemainingDevicePath is NULL.\r
+ @param ParentDevicePath Pointer to the parent device path.\r
+ @param CreateControllerNode TRUE to create the controller node.\r
+ @param Instance Instance number of the serial device.\r
+ The value will be set to the controller node\r
+ if CreateControllerNode is TRUE.\r
+ @param ParentIo A union type pointer to either Sio or PciIo.\r
+ @param PciSerialParameter The PCI serial parameter to be used by current serial device.\r
+ NULL for SIO serial device.\r
+ @param PciDeviceInfo The PCI device info for the current serial device.\r
+ NULL for SIO serial device.\r
+\r
+ @retval EFI_SUCCESS The serial device was created successfully.\r
+ @retval others The serial device wasn't created.\r
+**/\r
+EFI_STATUS\r
+CreateSerialDevice (\r
+ IN EFI_HANDLE Controller,\r
+ IN UART_DEVICE_PATH *Uart,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
+ IN BOOLEAN CreateControllerNode,\r
+ IN UINT32 Instance,\r
+ IN PARENT_IO_PROTOCOL_PTR ParentIo,\r
+ IN PCI_SERIAL_PARAMETER *PciSerialParameter, OPTIONAL\r
+ IN PCI_DEVICE_INFO *PciDeviceInfo OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SERIAL_DEV *SerialDevice;\r
+ UINT8 BarIndex;\r
+ UINT64 Offset;\r
+ UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;\r
+ UINT32 FlowControlMap;\r
+ ACPI_RESOURCE_HEADER_PTR Resources;\r
+ EFI_ACPI_IO_PORT_DESCRIPTOR *Io;\r
+ EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *FixedIo;\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AddressSpace;\r
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
+\r
+ BarIndex = 0;\r
+ Offset = 0;\r
+ FlowControl = NULL;\r
+ FlowControlMap = 0;\r
+\r
+ //\r
+ // Initialize the serial device instance\r
+ //\r
+ SerialDevice = AllocateCopyPool (sizeof (SERIAL_DEV), &gSerialDevTemplate);\r
+ ASSERT (SerialDevice != NULL);\r
+\r
+ SerialDevice->SerialIo.Mode = &(SerialDevice->SerialMode);\r
+ SerialDevice->ParentDevicePath = ParentDevicePath;\r
+ SerialDevice->PciDeviceInfo = PciDeviceInfo;\r
+ SerialDevice->Instance = Instance;\r
+\r
+ if (Uart != NULL) {\r
+ CopyMem (&SerialDevice->UartDevicePath, Uart, sizeof (UART_DEVICE_PATH));\r
+ FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);\r
+ if (IsUartFlowControlDevicePathNode (FlowControl)) {\r
+ FlowControlMap = ReadUnaligned32 (&FlowControl->FlowControlMap);\r
+ } else {\r
+ FlowControl = NULL;\r
+ }\r
+ }\r
+\r
+ //\r
+ // For PCI serial device, use the information from PCD\r
+ //\r
+ if (PciSerialParameter != NULL) {\r
+ BarIndex = (PciSerialParameter->BarIndex == PCI_BAR_ALL) ? 0 : PciSerialParameter->BarIndex;\r
+ Offset = PciSerialParameter->Offset;\r
+ if (PciSerialParameter->RegisterStride != 0) {\r
+ SerialDevice->RegisterStride = PciSerialParameter->RegisterStride;\r
+ }\r
+ if (PciSerialParameter->ClockRate != 0) {\r
+ SerialDevice->ClockRate = PciSerialParameter->ClockRate;\r
+ }\r
+ if (PciSerialParameter->ReceiveFifoDepth != 0) {\r
+ SerialDevice->ReceiveFifoDepth = PciSerialParameter->ReceiveFifoDepth;\r
+ }\r
+ if (PciSerialParameter->TransmitFifoDepth != 0) {\r
+ SerialDevice->TransmitFifoDepth = PciSerialParameter->TransmitFifoDepth;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade.\r
+ // DriverBindingStart() shouldn't create a handle with different UART device path.\r
+ //\r
+ if (!VerifyUartParameters (SerialDevice->ClockRate, SerialDevice->UartDevicePath.BaudRate, SerialDevice->UartDevicePath.DataBits,\r
+ SerialDevice->UartDevicePath.Parity, SerialDevice->UartDevicePath.StopBits, NULL, NULL\r
+ )) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto CreateError;\r
+ }\r
+\r
+ if (PciSerialParameter == NULL) {\r
+ Status = ParentIo.Sio->GetResources (ParentIo.Sio, &Resources);\r
+ } else {\r
+ Status = ParentIo.PciIo->GetBarAttributes (ParentIo.PciIo, BarIndex, NULL, (VOID **) &Resources);\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Get the base address information from ACPI resource descriptor.\r
+ // ACPI_IO_PORT_DESCRIPTOR and ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR are returned from Sio;\r
+ // ACPI_ADDRESS_SPACE_DESCRIPTOR is returned from PciIo.\r
+ //\r
+ while ((Resources.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) && (SerialDevice->BaseAddress == 0)) {\r
+ switch (Resources.SmallHeader->Byte) {\r
+ case ACPI_IO_PORT_DESCRIPTOR:\r
+ Io = (EFI_ACPI_IO_PORT_DESCRIPTOR *) Resources.SmallHeader;\r
+ if (Io->Length != 0) {\r
+ SerialDevice->BaseAddress = Io->BaseAddressMin;\r
+ }\r
+ break;\r
+\r
+ case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR:\r
+ FixedIo = (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *) Resources.SmallHeader;\r
+ if (FixedIo->Length != 0) {\r
+ SerialDevice->BaseAddress = FixedIo->BaseAddress;\r
+ }\r
+ break;\r
+\r
+ case ACPI_ADDRESS_SPACE_DESCRIPTOR:\r
+ AddressSpace = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Resources.SmallHeader;\r
+ if (AddressSpace->AddrLen != 0) {\r
+ if (AddressSpace->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {\r
+ SerialDevice->MmioAccess = TRUE;\r
+ }\r
+ SerialDevice->BaseAddress = AddressSpace->AddrRangeMin + Offset;\r
+ }\r
+ break;\r
+ }\r
+\r
+ if (Resources.SmallHeader->Bits.Type == 0) {\r
+ Resources.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) Resources.SmallHeader\r
+ + Resources.SmallHeader->Bits.Length\r
+ + sizeof (*Resources.SmallHeader));\r
+ } else {\r
+ Resources.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) Resources.LargeHeader\r
+ + Resources.LargeHeader->Length\r
+ + sizeof (*Resources.LargeHeader));\r
+ }\r
+ }\r
+ }\r
+\r
+ if (SerialDevice->BaseAddress == 0) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto CreateError;\r
+ }\r
+\r
+ SerialDevice->HardwareFlowControl = (BOOLEAN) (FlowControlMap == UART_FLOW_CONTROL_HARDWARE);\r
+\r
+ //\r
+ // Report status code the serial present\r
+ //\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_PROGRESS_CODE,\r
+ EFI_P_PC_PRESENCE_DETECT | EFI_PERIPHERAL_SERIAL_PORT,\r
+ SerialDevice->ParentDevicePath\r
+ );\r
+\r
+ if (!SerialPresent (SerialDevice)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_ERROR_CODE,\r
+ EFI_P_EC_NOT_DETECTED | EFI_PERIPHERAL_SERIAL_PORT,\r
+ SerialDevice->ParentDevicePath\r
+ );\r
+ goto CreateError;\r
+ }\r
+\r
+ //\r
+ // 1. Append Controller device path node.\r
+ //\r
+ if (CreateControllerNode) {\r
+ mControllerDevicePathTemplate.ControllerNumber = SerialDevice->Instance;\r
+ SerialDevice->DevicePath = AppendDevicePathNode (\r
+ SerialDevice->ParentDevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *) &mControllerDevicePathTemplate\r
+ );\r
+ SerialDevice->ContainsControllerNode = TRUE;\r
+ }\r
+\r
+ //\r
+ // 2. Append UART device path node.\r
+ // The Uart setings are zero here.\r
+ // SetAttribute() will update them to match the default setings.\r
+ //\r
+ TempDevicePath = SerialDevice->DevicePath;\r
+ if (TempDevicePath != NULL) {\r
+ SerialDevice->DevicePath = AppendDevicePathNode (\r
+ TempDevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath\r
+ );\r
+ FreePool (TempDevicePath);\r
+ } else {\r
+ SerialDevice->DevicePath = AppendDevicePathNode (\r
+ SerialDevice->ParentDevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath\r
+ );\r
+ }\r
+ //\r
+ // 3. Append the Flow Control device path node.\r
+ // Only produce the Flow Control node when remaining device path has it\r
+ //\r
+ if (FlowControl != NULL) {\r
+ TempDevicePath = SerialDevice->DevicePath;\r
+ if (TempDevicePath != NULL) {\r
+ SerialDevice->DevicePath = AppendDevicePathNode (\r
+ TempDevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *) FlowControl\r
+ );\r
+ FreePool (TempDevicePath);\r
+ }\r
+ }\r
+ ASSERT (SerialDevice->DevicePath != NULL);\r
+\r
+ //\r
+ // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.\r
+ //\r
+ SerialDevice->SerialMode.BaudRate = SerialDevice->UartDevicePath.BaudRate;\r
+ SerialDevice->SerialMode.DataBits = SerialDevice->UartDevicePath.DataBits;\r
+ SerialDevice->SerialMode.Parity = SerialDevice->UartDevicePath.Parity;\r
+ SerialDevice->SerialMode.StopBits = SerialDevice->UartDevicePath.StopBits;\r
+\r
+ //\r
+ // Issue a reset to initialize the COM port\r
+ //\r
+ Status = SerialDevice->SerialIo.Reset (&SerialDevice->SerialIo);\r
+ if (EFI_ERROR (Status)) {\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_ERROR_CODE,\r
+ EFI_P_EC_CONTROLLER_ERROR | EFI_PERIPHERAL_SERIAL_PORT,\r
+ SerialDevice->DevicePath\r
+ );\r
+ goto CreateError;\r
+ }\r
+\r
+ AddName (SerialDevice, Instance);\r
+ //\r
+ // Install protocol interfaces for the serial device.\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &SerialDevice->Handle,\r
+ &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,\r
+ &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto CreateError;\r
+ }\r
+ //\r
+ // Open For Child Device\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ PciSerialParameter != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,\r
+ (VOID **) &ParentIo,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ SerialDevice->Handle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ &SerialDevice->Handle,\r
+ &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,\r
+ &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,\r
+ NULL\r
+ );\r
+ }\r
+\r
+CreateError:\r
+ if (EFI_ERROR (Status)) {\r
+ if (SerialDevice->DevicePath != NULL) {\r
+ FreePool (SerialDevice->DevicePath);\r
+ }\r
+ if (SerialDevice->ControllerNameTable != NULL) {\r
+ FreeUnicodeStringTable (SerialDevice->ControllerNameTable);\r
+ }\r
+ FreePool (SerialDevice);\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Returns an array of pointers containing all the child serial device pointers.\r
+\r
+ @param Controller The parent controller handle.\r
+ @param IoProtocolGuid The protocol GUID, either equals to gEfiSioProtocolGuid\r
+ or equals to gEfiPciIoProtocolGuid.\r
+ @param Count Count of the serial devices.\r
+\r
+ @return An array of pointers containing all the child serial device pointers.\r
+**/\r
+SERIAL_DEV **\r
+GetChildSerialDevices (\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_GUID *IoProtocolGuid,\r
+ OUT UINTN *Count\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
+ UINTN EntryCount;\r
+ SERIAL_DEV **SerialDevices;\r
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
+ BOOLEAN OpenByDriver;\r
+\r
+ *Count = 0;\r
+ //\r
+ // If the SerialIo instance specified by RemainingDevicePath is already created,\r
+ // update the attributes/control.\r
+ //\r
+ Status = gBS->OpenProtocolInformation (\r
+ Controller,\r
+ IoProtocolGuid,\r
+ &OpenInfoBuffer,\r
+ &EntryCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ SerialDevices = AllocatePool (EntryCount * sizeof (SERIAL_DEV *));\r
+ ASSERT (SerialDevices != NULL);\r
+\r
+ *Count = 0;\r
+ OpenByDriver = FALSE;\r
+ for (Index = 0; Index < EntryCount; Index++) {\r
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
+ Status = gBS->OpenProtocol (\r
+ OpenInfoBuffer[Index].ControllerHandle,\r
+ &gEfiSerialIoProtocolGuid,\r
+ (VOID **) &SerialIo,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ SerialDevices[(*Count)++] = SERIAL_DEV_FROM_THIS (SerialIo);\r
+ }\r
+ }\r
+\r
+\r
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {\r
+ ASSERT (OpenInfoBuffer[Index].AgentHandle == gSerialControllerDriver.DriverBindingHandle);\r
+ OpenByDriver = TRUE;\r
+ }\r
+ }\r
+ if (OpenInfoBuffer != NULL) {\r
+ FreePool (OpenInfoBuffer);\r
+ }\r
+\r
+ ASSERT ((*Count == 0) || (OpenByDriver));\r
+\r
+ return SerialDevices;\r
+}\r
+\r
+/**\r
+ Start to management the controller passed in\r
+\r
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param Controller The handle of the controller to test.\r
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.\r
+\r
+ @return EFI_SUCCESS Driver is started successfully\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialControllerDriverStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *Node;\r
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
+ UINT32 ControllerNumber;\r
+ UART_DEVICE_PATH *Uart;\r
+ UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;\r
+ UINT32 Control;\r
+ PARENT_IO_PROTOCOL_PTR ParentIo;\r
+ ACPI_HID_DEVICE_PATH *Acpi;\r
+ EFI_GUID *IoProtocolGuid;\r
+ PCI_SERIAL_PARAMETER *PciSerialParameter;\r
+ PCI_SERIAL_PARAMETER DefaultPciSerialParameter;\r
+ PCI_TYPE00 Pci;\r
+ UINT32 PciSerialCount;\r
+ SERIAL_DEV **SerialDevices;\r
+ UINTN SerialDeviceCount;\r
+ PCI_DEVICE_INFO *PciDeviceInfo;\r
+ UINT64 Supports;\r
+ BOOLEAN ContainsControllerNode;\r
+\r
+ //\r
+ // Get the Parent Device Path\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &ParentDevicePath,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Report status code enable the serial\r
+ //\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_PROGRESS_CODE,\r
+ EFI_P_PC_ENABLE | EFI_PERIPHERAL_SERIAL_PORT,\r
+ ParentDevicePath\r
+ );\r
+\r
+ //\r
+ // Grab the IO abstraction we need to get any work done\r
+ //\r
+ IoProtocolGuid = &gEfiSioProtocolGuid;\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ IoProtocolGuid,\r
+ (VOID **) &ParentIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
+ IoProtocolGuid = &gEfiPciIoProtocolGuid;\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ IoProtocolGuid,\r
+ (VOID **) &ParentIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ }\r
+ ASSERT (!EFI_ERROR (Status) || Status == EFI_ALREADY_STARTED);\r
+\r
+ //\r
+ // Do nothing for END device path node\r
+ //\r
+ if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+\r
+ SerialDevices = GetChildSerialDevices (Controller, IoProtocolGuid, &SerialDeviceCount);\r
+ //\r
+ // If the SerialIo instance specified by RemainingDevicePath is already created,\r
+ // update the attributes/control.\r
+ //\r
+ if ((SerialDeviceCount != 0) && (RemainingDevicePath != NULL)) {\r
+ Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);\r
+ for (Index = 0; Index < SerialDeviceCount; Index++) {\r
+ if ((!SerialDevices[Index]->ContainsControllerNode && !ContainsControllerNode) ||\r
+ (SerialDevices[Index]->ContainsControllerNode && ContainsControllerNode && SerialDevices[Index]->Instance == ControllerNumber)\r
+ ) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ //\r
+ // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade.\r
+ // DriverBindingStart() shouldn't create a handle with different UART device path.\r
+ //\r
+ if (VerifyUartParameters (SerialDevices[Index]->ClockRate, Uart->BaudRate, Uart->DataBits,\r
+ (EFI_PARITY_TYPE) Uart->Parity, (EFI_STOP_BITS_TYPE) Uart->StopBits, NULL, NULL)) {\r
+ SerialIo = &SerialDevices[Index]->SerialIo;\r
+ Status = SerialIo->SetAttributes (\r
+ SerialIo,\r
+ Uart->BaudRate,\r
+ SerialIo->Mode->ReceiveFifoDepth,\r
+ SerialIo->Mode->Timeout,\r
+ (EFI_PARITY_TYPE) Uart->Parity,\r
+ Uart->DataBits,\r
+ (EFI_STOP_BITS_TYPE) Uart->StopBits\r
+ );\r
+ }\r
+ FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);\r
+ if (!EFI_ERROR (Status) && IsUartFlowControlDevicePathNode (FlowControl)) {\r
+ Status = SerialIo->GetControl (SerialIo, &Control);\r
+ if (!EFI_ERROR (Status)) {\r
+ if (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) {\r
+ Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
+ } else {\r
+ Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
+ }\r
+ //\r
+ // Clear the bits that are not allowed to pass to SetControl\r
+ //\r
+ Control &= (EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |\r
+ EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |\r
+ EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE);\r
+ Status = SerialIo->SetControl (SerialIo, Control);\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ if (Index != SerialDeviceCount) {\r
+ //\r
+ // Directly return if the SerialIo instance specified by RemainingDevicePath is found and updated.\r
+ // Otherwise continue to create the instance specified by RemainingDevicePath.\r
+ //\r
+ if (SerialDevices != NULL) {\r
+ FreePool (SerialDevices);\r
+ }\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ if (RemainingDevicePath != NULL) {\r
+ Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);\r
+ } else {\r
+ Uart = NULL;\r
+ }\r
+\r
+ PciDeviceInfo = NULL;\r
+ if (IoProtocolGuid == &gEfiSioProtocolGuid) {\r
+ Status = EFI_NOT_FOUND;\r
+ if (RemainingDevicePath == NULL || !ContainsControllerNode) {\r
+ Node = ParentDevicePath;\r
+ do {\r
+ Acpi = (ACPI_HID_DEVICE_PATH *) Node;\r
+ Node = NextDevicePathNode (Node);\r
+ } while (!IsDevicePathEnd (Node));\r
+ Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, Acpi->UID, ParentIo, NULL, NULL);\r
+ DEBUG ((EFI_D_INFO, "PciSioSerial: Create SIO child serial device - %r\n", Status));\r
+ }\r
+ } else {\r
+ Status = ParentIo.PciIo->Pci.Read (ParentIo.PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // PcdPciSerialParameters takes the higher priority.\r
+ //\r
+ PciSerialCount = 0;\r
+ for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) {\r
+ if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) &&\r
+ (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId)\r
+ ) {\r
+ PciSerialCount++;\r
+ }\r
+ }\r
+\r
+ if (SerialDeviceCount == 0) {\r
+ //\r
+ // Enable the IO & MEM decoding when creating the first child.\r
+ // Restore the PCI attributes when all children is destroyed (PciDeviceInfo->ChildCount == 0).\r
+ //\r
+ PciDeviceInfo = AllocatePool (sizeof (PCI_DEVICE_INFO));\r
+ PciDeviceInfo->ChildCount = 0;\r
+ PciDeviceInfo->PciIo = ParentIo.PciIo;\r
+ Status = ParentIo.PciIo->Attributes (\r
+ ParentIo.PciIo,\r
+ EfiPciIoAttributeOperationGet,\r
+ 0,\r
+ &PciDeviceInfo->PciAttributes\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = ParentIo.PciIo->Attributes (\r
+ ParentIo.PciIo,\r
+ EfiPciIoAttributeOperationSupported,\r
+ 0,\r
+ &Supports\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Supports &= EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY;\r
+ Status = ParentIo.PciIo->Attributes (\r
+ ParentIo.PciIo,\r
+ EfiPciIoAttributeOperationEnable,\r
+ Supports,\r
+ NULL\r
+ );\r
+ }\r
+ }\r
+ } else {\r
+ //\r
+ // Re-use the PciDeviceInfo stored in existing children.\r
+ //\r
+ PciDeviceInfo = SerialDevices[0]->PciDeviceInfo;\r
+ ASSERT (PciDeviceInfo != NULL);\r
+ }\r
+\r
+ Status = EFI_NOT_FOUND;\r
+ if (PciSerialCount <= 1) {\r
+ //\r
+ // PCI serial device contains only one UART\r
+ //\r
+ if (RemainingDevicePath == NULL || !ContainsControllerNode) {\r
+ //\r
+ // This PCI serial device is matched by class code in Supported()\r
+ //\r
+ if (PciSerialCount == 0) {\r
+ DefaultPciSerialParameter.VendorId = Pci.Hdr.VendorId;\r
+ DefaultPciSerialParameter.DeviceId = Pci.Hdr.DeviceId;\r
+ DefaultPciSerialParameter.BarIndex = 0;\r
+ DefaultPciSerialParameter.Offset = 0;\r
+ DefaultPciSerialParameter.RegisterStride = 0;\r
+ DefaultPciSerialParameter.ClockRate = 0;\r
+ PciSerialParameter = &DefaultPciSerialParameter;\r
+ } else if (PciSerialCount == 1) {\r
+ PciSerialParameter = PcdGetPtr (PcdPciSerialParameters);\r
+ }\r
+\r
+ Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, 0, ParentIo, PciSerialParameter, PciDeviceInfo);\r
+ DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device (single) - %r\n", Status));\r
+ if (!EFI_ERROR (Status)) {\r
+ PciDeviceInfo->ChildCount++;\r
+ }\r
+ }\r
+ } else {\r
+ //\r
+ // PCI serial device contains multiple UARTs\r
+ //\r
+ if (RemainingDevicePath == NULL || ContainsControllerNode) {\r
+ PciSerialCount = 0;\r
+ for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) {\r
+ if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) &&\r
+ (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId) &&\r
+ ((RemainingDevicePath == NULL) || (ControllerNumber == PciSerialCount))\r
+ ) {\r
+ //\r
+ // Create controller node when PCI serial device contains multiple UARTs\r
+ //\r
+ Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, TRUE, PciSerialCount, ParentIo, PciSerialParameter, PciDeviceInfo);\r
+ PciSerialCount++;\r
+ DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device (multiple) - %r\n", Status));\r
+ if (!EFI_ERROR (Status)) {\r
+ PciDeviceInfo->ChildCount++;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if (SerialDevices != NULL) {\r
+ FreePool (SerialDevices);\r
+ }\r
+\r
+ //\r
+ // For multiple PCI serial devices, set Status to SUCCESS if one child is created successfully\r
+ //\r
+ if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount != 0)) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ if (EFI_ERROR (Status) && (SerialDeviceCount == 0)) {\r
+ if (PciDeviceInfo != NULL) {\r
+ Status = ParentIo.PciIo->Attributes (\r
+ ParentIo.PciIo,\r
+ EfiPciIoAttributeOperationSet,\r
+ PciDeviceInfo->PciAttributes,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ FreePool (PciDeviceInfo);\r
+ }\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ IoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Disconnect this driver with the controller, uninstall related protocol instance\r
+\r
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param Controller The handle of the controller to test.\r
+ @param NumberOfChildren Number of child device.\r
+ @param ChildHandleBuffer A pointer to the remaining portion of a device path.\r
+\r
+ @retval EFI_SUCCESS Operation successfully\r
+ @retval EFI_DEVICE_ERROR Cannot stop the driver successfully\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialControllerDriverStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ BOOLEAN AllChildrenStopped;\r
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
+ SERIAL_DEV *SerialDevice;\r
+ VOID *IoProtocol;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ PCI_DEVICE_INFO *PciDeviceInfo;\r
+\r
+ PciDeviceInfo = NULL;\r
+\r
+ Status = gBS->HandleProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &DevicePath\r
+ );\r
+\r
+ //\r
+ // Report the status code disable the serial\r
+ //\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_PROGRESS_CODE,\r
+ EFI_P_PC_DISABLE | EFI_PERIPHERAL_SERIAL_PORT,\r
+ DevicePath\r
+ );\r
+\r
+ if (NumberOfChildren == 0) {\r
+ //\r
+ // Close the bus driver\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ &IoProtocol,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ !EFI_ERROR (Status) ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ AllChildrenStopped = TRUE;\r
+\r
+ for (Index = 0; Index < NumberOfChildren; Index++) {\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandleBuffer[Index],\r
+ &gEfiSerialIoProtocolGuid,\r
+ (VOID **) &SerialIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+\r
+ SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo);\r
+ ASSERT ((PciDeviceInfo == NULL) || (PciDeviceInfo == SerialDevice->PciDeviceInfo));\r
+ PciDeviceInfo = SerialDevice->PciDeviceInfo;\r
+\r
+ Status = gBS->CloseProtocol (\r
+ Controller,\r
+ PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index]\r
+ );\r
+\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ ChildHandleBuffer[Index],\r
+ &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,\r
+ &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->OpenProtocol (\r
+ Controller,\r
+ PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,\r
+ &IoProtocol,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index],\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ } else {\r
+ FreePool (SerialDevice->DevicePath);\r
+ FreeUnicodeStringTable (SerialDevice->ControllerNameTable);\r
+ FreePool (SerialDevice);\r
+\r
+ if (PciDeviceInfo != NULL) {\r
+ ASSERT (PciDeviceInfo->ChildCount != 0);\r
+ PciDeviceInfo->ChildCount--;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ AllChildrenStopped = FALSE;\r
+ }\r
+ }\r
+\r
+ if (!AllChildrenStopped) {\r
+ return EFI_DEVICE_ERROR;\r
+ } else {\r
+ //\r
+ // If all children are destroyed, restore the PCI attributes.\r
+ //\r
+ if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount == 0)) {\r
+ ASSERT (PciDeviceInfo->PciIo != NULL);\r
+ Status = PciDeviceInfo->PciIo->Attributes (\r
+ PciDeviceInfo->PciIo,\r
+ EfiPciIoAttributeOperationSet,\r
+ PciDeviceInfo->PciAttributes,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ FreePool (PciDeviceInfo);\r
+ }\r
+ return EFI_SUCCESS;\r
+ }\r
+}\r
--- /dev/null
+/** @file\r
+ Header file for PciSioSerial Driver\r
+\r
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SERIAL_H_\r
+#define _SERIAL_H_\r
+\r
+\r
+#include <Uefi.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+\r
+#include <Protocol/SuperIo.h>\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/SerialIo.h>\r
+#include <Protocol/DevicePath.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/ReportStatusCodeLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PrintLib.h>\r
+\r
+//\r
+// Driver Binding Externs\r
+//\r
+extern EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver;\r
+extern EFI_COMPONENT_NAME_PROTOCOL gPciSioSerialComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL gPciSioSerialComponentName2;\r
+\r
+#define SIO_SERIAL_PORT_NAME L"SIO Serial Port #%d"\r
+#define PCI_SERIAL_PORT_NAME L"PCI Serial Port #%d"\r
+#define SERIAL_PORT_NAME_LEN (sizeof (SIO_SERIAL_PORT_NAME) / sizeof (CHAR16) + MAXIMUM_VALUE_CHARACTERS)\r
+\r
+//\r
+// Internal Data Structures\r
+//\r
+#define TIMEOUT_STALL_INTERVAL 10\r
+\r
+#pragma pack(1)\r
+///\r
+/// PcdPciSerialParameters contains zero or more instances of the below structure.\r
+/// If a PCI device contains multiple UARTs, PcdPciSerialParameters needs to contain\r
+/// two instances of the below structure, with the VendorId and DeviceId equals to the\r
+/// device ID and vendor ID of the device. If the PCI device uses the first two BARs\r
+/// to support multiple UARTs, BarIndex of first instance equals to 0 and BarIndex of\r
+/// second one equals to 1; if the PCI device uses the first BAR to support multiple\r
+/// UARTs, BarIndex of both instance equals to 0 and Offset of first instance equals\r
+/// to 0 while Offset of second one equals to some value bigger or equal to 8.\r
+/// For certain UART whose register needs to be accessed in DWORD aligned address,\r
+/// RegisterStride equals to 4.\r
+///\r
+typedef struct {\r
+ UINT16 VendorId; ///< Vendor ID to match the PCI device. The value 0xFFFF terminates the list of entries.\r
+ UINT16 DeviceId; ///< Device ID to match the PCI device\r
+ UINT32 ClockRate; ///< UART clock rate. Set to 0 for default clock rate of 1843200 Hz\r
+ UINT64 Offset; ///< The byte offset into to the BAR\r
+ UINT8 BarIndex; ///< Which BAR to get the UART base address\r
+ UINT8 RegisterStride; ///< UART register stride in bytes. Set to 0 for default register stride of 1 byte.\r
+ UINT16 ReceiveFifoDepth; ///< UART receive FIFO depth in bytes. Set to 0 for a default FIFO depth of 16 bytes.\r
+ UINT16 TransmitFifoDepth; ///< UART transmit FIFO depth in bytes. Set to 0 for a default FIFO depth of 16 bytes.\r
+ UINT8 Reserved[2];\r
+} PCI_SERIAL_PARAMETER;\r
+#pragma pack()\r
+\r
+#define SERIAL_MAX_FIFO_SIZE 17 ///< Actual FIFO size is 16. FIFO based on circular wastes one unit.\r
+typedef struct {\r
+ UINT16 Head; ///< Head pointer of the FIFO. Empty when (Head == Tail).\r
+ UINT16 Tail; ///< Tail pointer of the FIFO. Full when ((Tail + 1) % SERIAL_MAX_FIFO_SIZE == Head).\r
+ UINT8 Data[SERIAL_MAX_FIFO_SIZE]; ///< Store the FIFO data.\r
+} SERIAL_DEV_FIFO;\r
+\r
+typedef union {\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_SIO_PROTOCOL *Sio;\r
+} PARENT_IO_PROTOCOL_PTR;\r
+\r
+typedef struct {\r
+ EFI_PCI_IO_PROTOCOL *PciIo; // Pointer to parent PciIo instance.\r
+ UINTN ChildCount; // Count of child SerialIo instance.\r
+ UINT64 PciAttributes; // Original PCI attributes.\r
+} PCI_DEVICE_INFO;\r
+\r
+typedef struct {\r
+ UINT32 Signature;\r
+ EFI_HANDLE Handle;\r
+ EFI_SERIAL_IO_PROTOCOL SerialIo;\r
+ EFI_SERIAL_IO_MODE SerialMode;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ UART_DEVICE_PATH UartDevicePath;\r
+\r
+ EFI_PHYSICAL_ADDRESS BaseAddress; ///< UART base address\r
+ BOOLEAN MmioAccess; ///< TRUE for MMIO, FALSE for IO\r
+ UINT8 RegisterStride; ///< UART Register Stride\r
+ UINT32 ClockRate; ///< UART clock rate\r
+\r
+ UINT16 ReceiveFifoDepth; ///< UART receive FIFO depth in bytes.\r
+ SERIAL_DEV_FIFO Receive; ///< The FIFO used to store received data\r
+\r
+ UINT16 TransmitFifoDepth; ///< UART transmit FIFO depth in bytes.\r
+ SERIAL_DEV_FIFO Transmit; ///< The FIFO used to store to-transmit data\r
+\r
+ BOOLEAN SoftwareLoopbackEnable;\r
+ BOOLEAN HardwareFlowControl;\r
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;\r
+ BOOLEAN ContainsControllerNode; ///< TRUE if the device produced contains Controller node\r
+ UINT32 Instance;\r
+ PCI_DEVICE_INFO *PciDeviceInfo;\r
+} SERIAL_DEV;\r
+\r
+#define SERIAL_DEV_SIGNATURE SIGNATURE_32 ('s', 'e', 'r', 'd')\r
+#define SERIAL_DEV_FROM_THIS(a) CR (a, SERIAL_DEV, SerialIo, SERIAL_DEV_SIGNATURE)\r
+\r
+//\r
+// Serial Driver Defaults\r
+//\r
+#define SERIAL_PORT_DEFAULT_TIMEOUT 1000000\r
+#define SERIAL_PORT_SUPPORT_CONTROL_MASK (EFI_SERIAL_CLEAR_TO_SEND | \\r
+ EFI_SERIAL_DATA_SET_READY | \\r
+ EFI_SERIAL_RING_INDICATE | \\r
+ EFI_SERIAL_CARRIER_DETECT | \\r
+ EFI_SERIAL_REQUEST_TO_SEND | \\r
+ EFI_SERIAL_DATA_TERMINAL_READY | \\r
+ EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | \\r
+ EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE | \\r
+ EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE | \\r
+ EFI_SERIAL_OUTPUT_BUFFER_EMPTY | \\r
+ EFI_SERIAL_INPUT_BUFFER_EMPTY)\r
+\r
+#define SERIAL_PORT_MIN_TIMEOUT 1 // 1 uS\r
+#define SERIAL_PORT_MAX_TIMEOUT 100000000 // 100 seconds\r
+//\r
+// UART Registers\r
+//\r
+#define SERIAL_REGISTER_THR 0 ///< WO Transmit Holding Register\r
+#define SERIAL_REGISTER_RBR 0 ///< RO Receive Buffer Register\r
+#define SERIAL_REGISTER_DLL 0 ///< R/W Divisor Latch LSB\r
+#define SERIAL_REGISTER_DLM 1 ///< R/W Divisor Latch MSB\r
+#define SERIAL_REGISTER_IER 1 ///< R/W Interrupt Enable Register\r
+#define SERIAL_REGISTER_IIR 2 ///< RO Interrupt Identification Register\r
+#define SERIAL_REGISTER_FCR 2 ///< WO FIFO Cotrol Register\r
+#define SERIAL_REGISTER_LCR 3 ///< R/W Line Control Register\r
+#define SERIAL_REGISTER_MCR 4 ///< R/W Modem Control Register\r
+#define SERIAL_REGISTER_LSR 5 ///< R/W Line Status Register\r
+#define SERIAL_REGISTER_MSR 6 ///< R/W Modem Status Register\r
+#define SERIAL_REGISTER_SCR 7 ///< R/W Scratch Pad Register\r
+#pragma pack(1)\r
+\r
+///\r
+/// Interrupt Enable Register\r
+///\r
+typedef union {\r
+ struct {\r
+ UINT8 Ravie : 1; ///< Receiver Data Available Interrupt Enable\r
+ UINT8 Theie : 1; ///< Transmistter Holding Register Empty Interrupt Enable\r
+ UINT8 Rie : 1; ///< Receiver Interrupt Enable\r
+ UINT8 Mie : 1; ///< Modem Interrupt Enable\r
+ UINT8 Reserved : 4;\r
+ } Bits;\r
+ UINT8 Data;\r
+} SERIAL_PORT_IER;\r
+\r
+///\r
+/// FIFO Control Register\r
+///\r
+typedef union {\r
+ struct {\r
+ UINT8 TrFIFOE : 1; ///< Transmit and Receive FIFO Enable\r
+ UINT8 ResetRF : 1; ///< Reset Reciever FIFO\r
+ UINT8 ResetTF : 1; ///< Reset Transmistter FIFO\r
+ UINT8 Dms : 1; ///< DMA Mode Select\r
+ UINT8 Reserved : 1;\r
+ UINT8 TrFIFO64 : 1; ///< Enable 64 byte FIFO\r
+ UINT8 Rtb : 2; ///< Receive Trigger Bits\r
+ } Bits;\r
+ UINT8 Data;\r
+} SERIAL_PORT_FCR;\r
+\r
+///\r
+/// Line Control Register\r
+///\r
+typedef union {\r
+ struct {\r
+ UINT8 SerialDB : 2; ///< Number of Serial Data Bits\r
+ UINT8 StopB : 1; ///< Number of Stop Bits\r
+ UINT8 ParEn : 1; ///< Parity Enable\r
+ UINT8 EvenPar : 1; ///< Even Parity Select\r
+ UINT8 SticPar : 1; ///< Sticky Parity\r
+ UINT8 BrCon : 1; ///< Break Control\r
+ UINT8 DLab : 1; ///< Divisor Latch Access Bit\r
+ } Bits;\r
+ UINT8 Data;\r
+} SERIAL_PORT_LCR;\r
+\r
+///\r
+/// Modem Control Register\r
+///\r
+typedef union {\r
+ struct {\r
+ UINT8 DtrC : 1; ///< Data Terminal Ready Control\r
+ UINT8 Rts : 1; ///< Request To Send Control\r
+ UINT8 Out1 : 1; ///< Output1\r
+ UINT8 Out2 : 1; ///< Output2, used to disable interrupt\r
+ UINT8 Lme : 1; ///< Loopback Mode Enable\r
+ UINT8 Reserved : 3;\r
+ } Bits;\r
+ UINT8 Data;\r
+} SERIAL_PORT_MCR;\r
+\r
+///\r
+/// Line Status Register\r
+///\r
+typedef union {\r
+ struct {\r
+ UINT8 Dr : 1; ///< Receiver Data Ready Status\r
+ UINT8 Oe : 1; ///< Overrun Error Status\r
+ UINT8 Pe : 1; ///< Parity Error Status\r
+ UINT8 Fe : 1; ///< Framing Error Status\r
+ UINT8 Bi : 1; ///< Break Interrupt Status\r
+ UINT8 Thre : 1; ///< Transmistter Holding Register Status\r
+ UINT8 Temt : 1; ///< Transmitter Empty Status\r
+ UINT8 FIFOe : 1; ///< FIFO Error Status\r
+ } Bits;\r
+ UINT8 Data;\r
+} SERIAL_PORT_LSR;\r
+\r
+///\r
+/// Modem Status Register\r
+///\r
+typedef union {\r
+ struct {\r
+ UINT8 DeltaCTS : 1; ///< Delta Clear To Send Status\r
+ UINT8 DeltaDSR : 1; ///< Delta Data Set Ready Status\r
+ UINT8 TrailingEdgeRI : 1; ///< Trailing Edge of Ring Indicator Status\r
+ UINT8 DeltaDCD : 1; ///< Delta Data Carrier Detect Status\r
+ UINT8 Cts : 1; ///< Clear To Send Status\r
+ UINT8 Dsr : 1; ///< Data Set Ready Status\r
+ UINT8 Ri : 1; ///< Ring Indicator Status\r
+ UINT8 Dcd : 1; ///< Data Carrier Detect Status\r
+ } Bits;\r
+ UINT8 Data;\r
+} SERIAL_PORT_MSR;\r
+\r
+#pragma pack()\r
+//\r
+// Define serial register I/O macros\r
+//\r
+#define READ_RBR(S) SerialReadRegister (S, SERIAL_REGISTER_RBR)\r
+#define READ_DLL(S) SerialReadRegister (S, SERIAL_REGISTER_DLL)\r
+#define READ_DLM(S) SerialReadRegister (S, SERIAL_REGISTER_DLM)\r
+#define READ_IER(S) SerialReadRegister (S, SERIAL_REGISTER_IER)\r
+#define READ_IIR(S) SerialReadRegister (S, SERIAL_REGISTER_IIR)\r
+#define READ_LCR(S) SerialReadRegister (S, SERIAL_REGISTER_LCR)\r
+#define READ_MCR(S) SerialReadRegister (S, SERIAL_REGISTER_MCR)\r
+#define READ_LSR(S) SerialReadRegister (S, SERIAL_REGISTER_LSR)\r
+#define READ_MSR(S) SerialReadRegister (S, SERIAL_REGISTER_MSR)\r
+#define READ_SCR(S) SerialReadRegister (S, SERIAL_REGISTER_SCR)\r
+\r
+#define WRITE_THR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_THR, D)\r
+#define WRITE_DLL(S, D) SerialWriteRegister (S, SERIAL_REGISTER_DLL, D)\r
+#define WRITE_DLM(S, D) SerialWriteRegister (S, SERIAL_REGISTER_DLM, D)\r
+#define WRITE_IER(S, D) SerialWriteRegister (S, SERIAL_REGISTER_IER, D)\r
+#define WRITE_FCR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_FCR, D)\r
+#define WRITE_LCR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_LCR, D)\r
+#define WRITE_MCR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_MCR, D)\r
+#define WRITE_LSR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_LSR, D)\r
+#define WRITE_MSR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_MSR, D)\r
+#define WRITE_SCR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_SCR, D)\r
+\r
+//\r
+// Prototypes\r
+// Driver model protocol interface\r
+//\r
+/**\r
+ Check to see if this driver supports the given controller\r
+\r
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param Controller The handle of the controller to test.\r
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.\r
+\r
+ @return EFI_SUCCESS This driver can support the given controller\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialControllerDriverSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+/**\r
+ Start to management the controller passed in\r
+\r
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param Controller The handle of the controller to test.\r
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.\r
+\r
+ @return EFI_SUCCESS Driver is started successfully\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialControllerDriverStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+/**\r
+ Disconnect this driver with the controller, uninstall related protocol instance\r
+\r
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param Controller The handle of the controller to test.\r
+ @param NumberOfChildren Number of child device.\r
+ @param ChildHandleBuffer A pointer to the remaining portion of a device path.\r
+\r
+ @retval EFI_SUCCESS Operation successfully\r
+ @retval EFI_DEVICE_ERROR Cannot stop the driver successfully\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialControllerDriverStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ );\r
+\r
+//\r
+// Serial I/O Protocol Interface\r
+//\r
+/**\r
+ Reset serial device.\r
+\r
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL\r
+\r
+ @retval EFI_SUCCESS Reset successfully\r
+ @retval EFI_DEVICE_ERROR Failed to reset\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialReset (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This\r
+ );\r
+\r
+/**\r
+ Set new attributes to a serial device.\r
+\r
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL\r
+ @param BaudRate The baudrate of the serial device\r
+ @param ReceiveFifoDepth The depth of receive FIFO buffer\r
+ @param Timeout The request timeout for a single char\r
+ @param Parity The type of parity used in serial device\r
+ @param DataBits Number of databits used in serial device\r
+ @param StopBits Number of stopbits used in serial device\r
+\r
+ @retval EFI_SUCCESS The new attributes were set\r
+ @retval EFI_INVALID_PARAMETERS One or more attributes have an unsupported value\r
+ @retval EFI_UNSUPPORTED Data Bits can not set to 5 or 6\r
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return)\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialSetAttributes (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN UINT64 BaudRate,\r
+ IN UINT32 ReceiveFifoDepth,\r
+ IN UINT32 Timeout,\r
+ IN EFI_PARITY_TYPE Parity,\r
+ IN UINT8 DataBits,\r
+ IN EFI_STOP_BITS_TYPE StopBits\r
+ );\r
+\r
+/**\r
+ Set Control Bits.\r
+\r
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL\r
+ @param Control Control bits that can be settable\r
+\r
+ @retval EFI_SUCCESS New Control bits were set successfully\r
+ @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialSetControl (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN UINT32 Control\r
+ );\r
+\r
+/**\r
+ Get ControlBits.\r
+\r
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL\r
+ @param Control Control signals of the serial device\r
+\r
+ @retval EFI_SUCCESS Get Control signals successfully\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialGetControl (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ OUT UINT32 *Control\r
+ );\r
+\r
+/**\r
+ Write the specified number of bytes to serial device.\r
+\r
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL\r
+ @param BufferSize On input the size of 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 were written successfully\r
+ @retval EFI_DEVICE_ERROR The device reported an error\r
+ @retval EFI_TIMEOUT The write operation was stopped due to timeout\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialWrite (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN OUT UINTN *BufferSize,\r
+ IN VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Read the specified number of bytes from serial device.\r
+\r
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL\r
+ @param BufferSize On input the size of 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 were read successfully\r
+ @retval EFI_DEVICE_ERROR The device reported an error\r
+ @retval EFI_TIMEOUT The read operation was stopped due to timeout\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialRead (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+//\r
+// Internal Functions\r
+//\r
+/**\r
+ Use scratchpad register to test if this serial port is present.\r
+\r
+ @param SerialDevice Pointer to serial device structure\r
+\r
+ @return if this serial port is present\r
+**/\r
+BOOLEAN\r
+SerialPresent (\r
+ IN SERIAL_DEV *SerialDevice\r
+ );\r
+\r
+/**\r
+ Detect whether specific FIFO is full or not.\r
+\r
+ @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO\r
+\r
+ @return whether specific FIFO is full or not\r
+\r
+**/\r
+BOOLEAN\r
+SerialFifoFull (\r
+ IN SERIAL_DEV_FIFO *Fifo\r
+ );\r
+\r
+/**\r
+ Detect whether specific FIFO is empty or not.\r
+ \r
+ @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO\r
+\r
+ @return whether specific FIFO is empty or not\r
+\r
+**/\r
+BOOLEAN\r
+SerialFifoEmpty (\r
+ IN SERIAL_DEV_FIFO *Fifo\r
+ );\r
+\r
+/**\r
+ Add data to specific FIFO.\r
+\r
+ @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO\r
+ @param Data the data added to FIFO\r
+\r
+ @retval EFI_SUCCESS Add data to specific FIFO successfully\r
+ @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full\r
+\r
+**/\r
+EFI_STATUS\r
+SerialFifoAdd (\r
+ IN SERIAL_DEV_FIFO *Fifo,\r
+ IN UINT8 Data\r
+ );\r
+\r
+/**\r
+ Remove data from specific FIFO.\r
+\r
+ @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO\r
+ @param Data the data removed from FIFO\r
+\r
+ @retval EFI_SUCCESS Remove data from specific FIFO successfully\r
+ @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty\r
+\r
+**/\r
+EFI_STATUS\r
+SerialFifoRemove (\r
+ IN SERIAL_DEV_FIFO *Fifo,\r
+ OUT UINT8 *Data\r
+ );\r
+\r
+/**\r
+ Reads and writes all avaliable data.\r
+\r
+ @param SerialDevice The device to flush\r
+\r
+ @retval EFI_SUCCESS Data was read/written successfully.\r
+ @retval EFI_OUT_OF_RESOURCE Failed because software receive FIFO is full. Note, when\r
+ this happens, pending writes are not done.\r
+\r
+**/\r
+EFI_STATUS\r
+SerialReceiveTransmit (\r
+ IN SERIAL_DEV *SerialDevice\r
+ );\r
+\r
+/**\r
+ Read serial port.\r
+\r
+ @param SerialDev Pointer to serial device\r
+ @param Offset Offset in register group\r
+\r
+ @return Data read from serial port\r
+**/\r
+UINT8\r
+SerialReadRegister (\r
+ IN SERIAL_DEV *SerialDev,\r
+ IN UINT32 Offset\r
+ );\r
+\r
+/**\r
+ Write serial port.\r
+\r
+ @param SerialDev Pointer to serial device\r
+ @param Offset Offset in register group\r
+ @param Data data which is to be written to some serial port register\r
+**/\r
+VOID\r
+SerialWriteRegister (\r
+ IN SERIAL_DEV *SerialDev,\r
+ IN UINT32 Offset,\r
+ IN UINT8 Data\r
+ );\r
+\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ );\r
+\r
+/**\r
+ Add the component name for the serial io device\r
+\r
+ @param SerialDevice A pointer to the SERIAL_DEV instance.\r
+ @param Uid Unique ID for the serial device.\r
+**/\r
+VOID\r
+AddName (\r
+ IN SERIAL_DEV *SerialDevice,\r
+ IN UINT32 Uid\r
+ );\r
+\r
+/**\r
+ Checks whether the UART parameters are valid and computes the Divisor.\r
+\r
+ @param ClockRate The clock rate of the serial device used to verify\r
+ the BaudRate. Do not verify the BaudRate if it's 0.\r
+ @param BaudRate The requested baudrate of the serial device.\r
+ @param DataBits Number of databits used in serial device.\r
+ @param Parity The type of parity used in serial device.\r
+ @param StopBits Number of stopbits used in serial device.\r
+ @param Divisor Return the divisor if ClockRate is not 0.\r
+ @param ActualBaudRate Return the actual supported baudrate without\r
+ exceeding BaudRate. NULL means baudrate degradation\r
+ is not allowed.\r
+ If the requested BaudRate is not supported, the routine\r
+ returns TRUE and the Actual Baud Rate when ActualBaudRate\r
+ is not NULL, returns FALSE when ActualBaudRate is NULL.\r
+\r
+ @retval TRUE The UART parameters are valid.\r
+ @retval FALSE The UART parameters are not valid.\r
+**/\r
+BOOLEAN\r
+VerifyUartParameters (\r
+ IN UINT32 ClockRate,\r
+ IN UINT64 BaudRate,\r
+ IN UINT8 DataBits,\r
+ IN EFI_PARITY_TYPE Parity,\r
+ IN EFI_STOP_BITS_TYPE StopBits,\r
+ OUT UINT64 *Divisor,\r
+ OUT UINT64 *ActualBaudRate\r
+ );\r
+\r
+/**\r
+ Skip the optional Controller device path node and return the\r
+ pointer to the next device path node.\r
+\r
+ @param DevicePath Pointer to the device path.\r
+ @param ContainsControllerNode Returns TRUE if the Controller device path exists.\r
+ @param ControllerNumber Returns the Controller Number if Controller device path exists.\r
+\r
+ @return Pointer to the next device path node.\r
+**/\r
+UART_DEVICE_PATH *\r
+SkipControllerDevicePathNode (\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ BOOLEAN *ContainsControllerNode,\r
+ UINT32 *ControllerNumber\r
+ );\r
+\r
+/**\r
+ Check the device path node whether it's the Flow Control node or not.\r
+\r
+ @param[in] FlowControl The device path node to be checked.\r
+ \r
+ @retval TRUE It's the Flow Control node.\r
+ @retval FALSE It's not.\r
+\r
+**/\r
+BOOLEAN\r
+IsUartFlowControlDevicePathNode (\r
+ IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl\r
+ );\r
+#endif\r
--- /dev/null
+/** @file\r
+ SerialIo implementation for PCI or SIO UARTs.\r
+\r
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Serial.h"\r
+\r
+/**\r
+ Skip the optional Controller device path node and return the\r
+ pointer to the next device path node.\r
+\r
+ @param DevicePath Pointer to the device path.\r
+ @param ContainsControllerNode Returns TRUE if the Controller device path exists.\r
+ @param ControllerNumber Returns the Controller Number if Controller device path exists.\r
+\r
+ @return Pointer to the next device path node.\r
+**/\r
+UART_DEVICE_PATH *\r
+SkipControllerDevicePathNode (\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ BOOLEAN *ContainsControllerNode,\r
+ UINT32 *ControllerNumber\r
+ )\r
+{\r
+ if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) &&\r
+ (DevicePathSubType (DevicePath) == HW_CONTROLLER_DP)\r
+ ) {\r
+ if (ContainsControllerNode != NULL) {\r
+ *ContainsControllerNode = TRUE;\r
+ }\r
+ if (ControllerNumber != NULL) {\r
+ *ControllerNumber = ((CONTROLLER_DEVICE_PATH *) DevicePath)->ControllerNumber;\r
+ }\r
+ DevicePath = NextDevicePathNode (DevicePath);\r
+ } else {\r
+ if (ContainsControllerNode != NULL) {\r
+ *ContainsControllerNode = FALSE;\r
+ }\r
+ }\r
+ return (UART_DEVICE_PATH *) DevicePath;\r
+}\r
+\r
+/**\r
+ Checks whether the UART parameters are valid and computes the Divisor.\r
+\r
+ @param ClockRate The clock rate of the serial device used to verify\r
+ the BaudRate. Do not verify the BaudRate if it's 0.\r
+ @param BaudRate The requested baudrate of the serial device.\r
+ @param DataBits Number of databits used in serial device.\r
+ @param Parity The type of parity used in serial device.\r
+ @param StopBits Number of stopbits used in serial device.\r
+ @param Divisor Return the divisor if ClockRate is not 0.\r
+ @param ActualBaudRate Return the actual supported baudrate without\r
+ exceeding BaudRate. NULL means baudrate degradation\r
+ is not allowed.\r
+ If the requested BaudRate is not supported, the routine\r
+ returns TRUE and the Actual Baud Rate when ActualBaudRate\r
+ is not NULL, returns FALSE when ActualBaudRate is NULL.\r
+\r
+ @retval TRUE The UART parameters are valid.\r
+ @retval FALSE The UART parameters are not valid.\r
+**/\r
+BOOLEAN\r
+VerifyUartParameters (\r
+ IN UINT32 ClockRate,\r
+ IN UINT64 BaudRate,\r
+ IN UINT8 DataBits,\r
+ IN EFI_PARITY_TYPE Parity,\r
+ IN EFI_STOP_BITS_TYPE StopBits,\r
+ OUT UINT64 *Divisor,\r
+ OUT UINT64 *ActualBaudRate\r
+ )\r
+{\r
+ UINT64 Remainder;\r
+ UINT32 ComputedBaudRate;\r
+ UINT64 ComputedDivisor;\r
+ UINT64 Percent;\r
+\r
+ if ((DataBits < 5) || (DataBits > 8) ||\r
+ (Parity < NoParity) || (Parity > SpaceParity) ||\r
+ (StopBits < OneStopBit) || (StopBits > TwoStopBits) ||\r
+ ((DataBits == 5) && (StopBits == TwoStopBits)) ||\r
+ ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits))\r
+ ) {\r
+ return FALSE;\r
+ } \r
+\r
+ //\r
+ // Do not verify the baud rate if clock rate is unknown (0).\r
+ //\r
+ if (ClockRate == 0) {\r
+ return TRUE;\r
+ }\r
+\r
+ //\r
+ // Compute divisor use to program the baud rate using a round determination\r
+ // Divisor = ClockRate / 16 / BaudRate = ClockRate / (16 * BaudRate)\r
+ // = ClockRate / (BaudRate << 4)\r
+ //\r
+ ComputedDivisor = DivU64x64Remainder (ClockRate, LShiftU64 (BaudRate, 4), &Remainder);\r
+ //\r
+ // Round Divisor up by 1 if the Remainder is more than half (16 * BaudRate)\r
+ // BaudRate * 16 / 2 = BaudRate * 8 = (BaudRate << 3)\r
+ //\r
+ if (Remainder >= LShiftU64 (BaudRate, 3)) {\r
+ ComputedDivisor++;\r
+ }\r
+ //\r
+ // If the computed divisor is larger than the maximum value that can be programmed\r
+ // into the UART, then the requested baud rate can not be supported.\r
+ //\r
+ if (ComputedDivisor > MAX_UINT16) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // If the computed divisor is 0, then use a computed divisor of 1, which will select\r
+ // the maximum supported baud rate.\r
+ //\r
+ if (ComputedDivisor == 0) {\r
+ ComputedDivisor = 1;\r
+ }\r
+\r
+ //\r
+ // Actual baud rate that the serial port will be programmed for\r
+ // should be with in 4% of requested one.\r
+ //\r
+ ComputedBaudRate = ClockRate / ((UINT16) ComputedDivisor << 4);\r
+ if (ComputedBaudRate == 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ Percent = DivU64x32 (MultU64x32 (BaudRate, 100), ComputedBaudRate);\r
+ DEBUG ((EFI_D_INFO, "ClockRate = %d\n", ClockRate));\r
+ DEBUG ((EFI_D_INFO, "Divisor = %ld\n", ComputedDivisor));\r
+ DEBUG ((EFI_D_INFO, "BaudRate/Actual (%ld/%d) = %d%%\n", BaudRate, ComputedBaudRate, Percent));\r
+\r
+ //\r
+ // If the requested BaudRate is not supported:\r
+ // Returns TRUE and the Actual Baud Rate when ActualBaudRate is not NULL;\r
+ // Returns FALSE when ActualBaudRate is NULL.\r
+ //\r
+ if ((Percent >= 96) && (Percent <= 104)) {\r
+ if (ActualBaudRate != NULL) {\r
+ *ActualBaudRate = BaudRate;\r
+ }\r
+ if (Divisor != NULL) {\r
+ *Divisor = ComputedDivisor;\r
+ }\r
+ return TRUE;\r
+ }\r
+ if (ComputedBaudRate < BaudRate) {\r
+ if (ActualBaudRate != NULL) {\r
+ *ActualBaudRate = ComputedBaudRate;\r
+ }\r
+ if (Divisor != NULL) {\r
+ *Divisor = ComputedDivisor;\r
+ }\r
+ return TRUE;\r
+ }\r
+\r
+ //\r
+ // ActualBaudRate is higher than requested baud rate and more than 4% \r
+ // higher than the requested value. Increment Divisor if it is less \r
+ // than MAX_UINT16 and computed baud rate with new divisor.\r
+ //\r
+ if (ComputedDivisor == MAX_UINT16) {\r
+ return FALSE;\r
+ }\r
+ ComputedDivisor++;\r
+ ComputedBaudRate = ClockRate / ((UINT16) ComputedDivisor << 4);\r
+ if (ComputedBaudRate == 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "ClockRate = %d\n", ClockRate));\r
+ DEBUG ((EFI_D_INFO, "Divisor = %ld\n", ComputedDivisor));\r
+ DEBUG ((EFI_D_INFO, "BaudRate/Actual (%ld/%d) = %d%%\n", BaudRate, ComputedBaudRate, Percent));\r
+\r
+ if (ActualBaudRate != NULL) {\r
+ *ActualBaudRate = ComputedBaudRate;\r
+ }\r
+ if (Divisor != NULL) {\r
+ *Divisor = ComputedDivisor;\r
+ }\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Detect whether specific FIFO is full or not.\r
+\r
+ @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO\r
+\r
+ @return whether specific FIFO is full or not\r
+**/\r
+BOOLEAN\r
+SerialFifoFull (\r
+ IN SERIAL_DEV_FIFO *Fifo\r
+ )\r
+{\r
+ return (BOOLEAN) (((Fifo->Tail + 1) % SERIAL_MAX_FIFO_SIZE) == Fifo->Head);\r
+}\r
+\r
+/**\r
+ Detect whether specific FIFO is empty or not.\r
+ \r
+ @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO\r
+\r
+ @return whether specific FIFO is empty or not\r
+**/\r
+BOOLEAN\r
+SerialFifoEmpty (\r
+ IN SERIAL_DEV_FIFO *Fifo\r
+ )\r
+\r
+{\r
+ return (BOOLEAN) (Fifo->Head == Fifo->Tail);\r
+}\r
+\r
+/**\r
+ Add data to specific FIFO.\r
+\r
+ @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO\r
+ @param Data the data added to FIFO\r
+\r
+ @retval EFI_SUCCESS Add data to specific FIFO successfully\r
+ @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full\r
+**/\r
+EFI_STATUS\r
+SerialFifoAdd (\r
+ IN OUT SERIAL_DEV_FIFO *Fifo,\r
+ IN UINT8 Data\r
+ )\r
+{\r
+ //\r
+ // if FIFO full can not add data\r
+ //\r
+ if (SerialFifoFull (Fifo)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // FIFO is not full can add data\r
+ //\r
+ Fifo->Data[Fifo->Tail] = Data;\r
+ Fifo->Tail = (Fifo->Tail + 1) % SERIAL_MAX_FIFO_SIZE;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Remove data from specific FIFO.\r
+\r
+ @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO\r
+ @param Data the data removed from FIFO\r
+\r
+ @retval EFI_SUCCESS Remove data from specific FIFO successfully\r
+ @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty\r
+\r
+**/\r
+EFI_STATUS\r
+SerialFifoRemove (\r
+ IN OUT SERIAL_DEV_FIFO *Fifo,\r
+ OUT UINT8 *Data\r
+ )\r
+{\r
+ //\r
+ // if FIFO is empty, no data can remove\r
+ //\r
+ if (SerialFifoEmpty (Fifo)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // FIFO is not empty, can remove data\r
+ //\r
+ *Data = Fifo->Data[Fifo->Head];\r
+ Fifo->Head = (Fifo->Head + 1) % SERIAL_MAX_FIFO_SIZE;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Reads and writes all avaliable data.\r
+\r
+ @param SerialDevice The device to transmit.\r
+\r
+ @retval EFI_SUCCESS Data was read/written successfully.\r
+ @retval EFI_OUT_OF_RESOURCE Failed because software receive FIFO is full. Note, when\r
+ this happens, pending writes are not done.\r
+\r
+**/\r
+EFI_STATUS\r
+SerialReceiveTransmit (\r
+ IN SERIAL_DEV *SerialDevice\r
+ )\r
+\r
+{\r
+ SERIAL_PORT_LSR Lsr;\r
+ UINT8 Data;\r
+ BOOLEAN ReceiveFifoFull;\r
+ SERIAL_PORT_MSR Msr;\r
+ SERIAL_PORT_MCR Mcr;\r
+ UINTN TimeOut;\r
+\r
+ Data = 0;\r
+\r
+ //\r
+ // Begin the read or write\r
+ //\r
+ if (SerialDevice->SoftwareLoopbackEnable) {\r
+ do {\r
+ ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive);\r
+ if (!SerialFifoEmpty (&SerialDevice->Transmit)) {\r
+ SerialFifoRemove (&SerialDevice->Transmit, &Data);\r
+ if (ReceiveFifoFull) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ SerialFifoAdd (&SerialDevice->Receive, Data);\r
+ }\r
+ } while (!SerialFifoEmpty (&SerialDevice->Transmit));\r
+ } else {\r
+ ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive);\r
+ //\r
+ // For full handshake flow control, tell the peer to send data\r
+ // if receive buffer is available.\r
+ //\r
+ if (SerialDevice->HardwareFlowControl &&\r
+ !FeaturePcdGet(PcdSerialUseHalfHandshake)&&\r
+ !ReceiveFifoFull\r
+ ) {\r
+ Mcr.Data = READ_MCR (SerialDevice);\r
+ Mcr.Bits.Rts = 1;\r
+ WRITE_MCR (SerialDevice, Mcr.Data);\r
+ }\r
+ do {\r
+ Lsr.Data = READ_LSR (SerialDevice);\r
+\r
+ //\r
+ // Flush incomming data to prevent a an overrun during a long write\r
+ //\r
+ if ((Lsr.Bits.Dr == 1) && !ReceiveFifoFull) {\r
+ ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive);\r
+ if (!ReceiveFifoFull) {\r
+ if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Oe == 1 || Lsr.Bits.Pe == 1 || Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) {\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_ERROR_CODE,\r
+ EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,\r
+ SerialDevice->DevicePath\r
+ );\r
+ if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Pe == 1|| Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) {\r
+ Data = READ_RBR (SerialDevice);\r
+ continue;\r
+ }\r
+ }\r
+\r
+ Data = READ_RBR (SerialDevice);\r
+\r
+ SerialFifoAdd (&SerialDevice->Receive, Data);\r
+ \r
+ //\r
+ // For full handshake flow control, if receive buffer full\r
+ // tell the peer to stop sending data.\r
+ //\r
+ if (SerialDevice->HardwareFlowControl &&\r
+ !FeaturePcdGet(PcdSerialUseHalfHandshake) &&\r
+ SerialFifoFull (&SerialDevice->Receive)\r
+ ) {\r
+ Mcr.Data = READ_MCR (SerialDevice);\r
+ Mcr.Bits.Rts = 0;\r
+ WRITE_MCR (SerialDevice, Mcr.Data);\r
+ }\r
+\r
+\r
+ continue;\r
+ } else {\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_PROGRESS_CODE,\r
+ EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER | EFI_PERIPHERAL_SERIAL_PORT,\r
+ SerialDevice->DevicePath\r
+ );\r
+ }\r
+ }\r
+ //\r
+ // Do the write\r
+ //\r
+ if (Lsr.Bits.Thre == 1 && !SerialFifoEmpty (&SerialDevice->Transmit)) {\r
+ //\r
+ // Make sure the transmit data will not be missed\r
+ //\r
+ if (SerialDevice->HardwareFlowControl) {\r
+ //\r
+ // For half handshake flow control assert RTS before sending.\r
+ //\r
+ if (FeaturePcdGet(PcdSerialUseHalfHandshake)) {\r
+ Mcr.Data = READ_MCR (SerialDevice);\r
+ Mcr.Bits.Rts= 0;\r
+ WRITE_MCR (SerialDevice, Mcr.Data);\r
+ }\r
+ //\r
+ // Wait for CTS\r
+ //\r
+ TimeOut = 0;\r
+ Msr.Data = READ_MSR (SerialDevice);\r
+ while ((Msr.Bits.Dcd == 1) && ((Msr.Bits.Cts == 0) ^ FeaturePcdGet(PcdSerialUseHalfHandshake))) {\r
+ gBS->Stall (TIMEOUT_STALL_INTERVAL);\r
+ TimeOut++;\r
+ if (TimeOut > 5) {\r
+ break;\r
+ }\r
+\r
+ Msr.Data = READ_MSR (SerialDevice);\r
+ }\r
+\r
+ if ((Msr.Bits.Dcd == 0) || ((Msr.Bits.Cts == 1) ^ FeaturePcdGet(PcdSerialUseHalfHandshake))) {\r
+ SerialFifoRemove (&SerialDevice->Transmit, &Data);\r
+ WRITE_THR (SerialDevice, Data);\r
+ }\r
+\r
+ //\r
+ // For half handshake flow control, tell DCE we are done.\r
+ //\r
+ if (FeaturePcdGet(PcdSerialUseHalfHandshake)) {\r
+ Mcr.Data = READ_MCR (SerialDevice);\r
+ Mcr.Bits.Rts = 1;\r
+ WRITE_MCR (SerialDevice, Mcr.Data);\r
+ }\r
+ } else {\r
+ SerialFifoRemove (&SerialDevice->Transmit, &Data);\r
+ WRITE_THR (SerialDevice, Data);\r
+ }\r
+ }\r
+ } while (Lsr.Bits.Thre == 1 && !SerialFifoEmpty (&SerialDevice->Transmit));\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Flush the serial hardware transmit FIFO and shift register.\r
+\r
+ @param SerialDevice The device to flush.\r
+**/\r
+VOID\r
+SerialFlushTransmitFifo (\r
+ SERIAL_DEV *SerialDevice\r
+ )\r
+{\r
+ SERIAL_PORT_LSR Lsr;\r
+\r
+ //\r
+ // Wait for the serial port to be ready, to make sure both the transmit FIFO\r
+ // and shift register empty.\r
+ //\r
+ do {\r
+ Lsr.Data = READ_LSR (SerialDevice);\r
+ } while (Lsr.Bits.Temt == 0);\r
+}\r
+\r
+//\r
+// Interface Functions\r
+//\r
+/**\r
+ Reset serial device.\r
+\r
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL\r
+\r
+ @retval EFI_SUCCESS Reset successfully\r
+ @retval EFI_DEVICE_ERROR Failed to reset\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialReset (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SERIAL_DEV *SerialDevice;\r
+ SERIAL_PORT_LCR Lcr;\r
+ SERIAL_PORT_IER Ier;\r
+ SERIAL_PORT_MCR Mcr;\r
+ SERIAL_PORT_FCR Fcr;\r
+ EFI_TPL Tpl;\r
+ UINT32 Control;\r
+\r
+ SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
+\r
+ //\r
+ // Report the status code reset the serial\r
+ //\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_PROGRESS_CODE,\r
+ EFI_P_PC_RESET | EFI_PERIPHERAL_SERIAL_PORT,\r
+ SerialDevice->DevicePath\r
+ );\r
+\r
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ SerialFlushTransmitFifo (SerialDevice);\r
+\r
+ //\r
+ // Make sure DLAB is 0.\r
+ //\r
+ Lcr.Data = READ_LCR (SerialDevice);\r
+ Lcr.Bits.DLab = 0;\r
+ WRITE_LCR (SerialDevice, Lcr.Data);\r
+\r
+ //\r
+ // Turn off all interrupts\r
+ //\r
+ Ier.Data = READ_IER (SerialDevice);\r
+ Ier.Bits.Ravie = 0;\r
+ Ier.Bits.Theie = 0;\r
+ Ier.Bits.Rie = 0;\r
+ Ier.Bits.Mie = 0;\r
+ WRITE_IER (SerialDevice, Ier.Data);\r
+\r
+ //\r
+ // Reset the FIFO\r
+ //\r
+ Fcr.Data = 0;\r
+ Fcr.Bits.TrFIFOE = 0;\r
+ WRITE_FCR (SerialDevice, Fcr.Data);\r
+\r
+ //\r
+ // Turn off loopback and disable device interrupt.\r
+ //\r
+ Mcr.Data = READ_MCR (SerialDevice);\r
+ Mcr.Bits.Out1 = 0;\r
+ Mcr.Bits.Out2 = 0;\r
+ Mcr.Bits.Lme = 0;\r
+ WRITE_MCR (SerialDevice, Mcr.Data);\r
+\r
+ //\r
+ // Clear the scratch pad register\r
+ //\r
+ WRITE_SCR (SerialDevice, 0);\r
+\r
+ //\r
+ // Enable FIFO\r
+ //\r
+ Fcr.Bits.TrFIFOE = 1;\r
+ if (SerialDevice->ReceiveFifoDepth > 16) {\r
+ Fcr.Bits.TrFIFO64 = 1;\r
+ }\r
+ Fcr.Bits.ResetRF = 1;\r
+ Fcr.Bits.ResetTF = 1;\r
+ WRITE_FCR (SerialDevice, Fcr.Data);\r
+\r
+ //\r
+ // Go set the current attributes\r
+ //\r
+ Status = This->SetAttributes (\r
+ This,\r
+ This->Mode->BaudRate,\r
+ This->Mode->ReceiveFifoDepth,\r
+ This->Mode->Timeout,\r
+ (EFI_PARITY_TYPE) This->Mode->Parity,\r
+ (UINT8) This->Mode->DataBits,\r
+ (EFI_STOP_BITS_TYPE) This->Mode->StopBits\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->RestoreTPL (Tpl);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Go set the current control bits\r
+ //\r
+ Control = 0;\r
+ if (SerialDevice->HardwareFlowControl) {\r
+ Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
+ }\r
+ if (SerialDevice->SoftwareLoopbackEnable) {\r
+ Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;\r
+ }\r
+ Status = This->SetControl (\r
+ This,\r
+ Control\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->RestoreTPL (Tpl);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Reset the software FIFO\r
+ //\r
+ SerialDevice->Receive.Head = SerialDevice->Receive.Tail = 0;\r
+ SerialDevice->Transmit.Head = SerialDevice->Transmit.Tail = 0;\r
+ gBS->RestoreTPL (Tpl);\r
+\r
+ //\r
+ // Device reset is complete\r
+ //\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Set new attributes to a serial device.\r
+\r
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL\r
+ @param BaudRate The baudrate of the serial device\r
+ @param ReceiveFifoDepth The depth of receive FIFO buffer\r
+ @param Timeout The request timeout for a single char\r
+ @param Parity The type of parity used in serial device\r
+ @param DataBits Number of databits used in serial device\r
+ @param StopBits Number of stopbits used in serial device\r
+\r
+ @retval EFI_SUCCESS The new attributes were set\r
+ @retval EFI_INVALID_PARAMETERS One or more attributes have an unsupported value\r
+ @retval EFI_UNSUPPORTED Data Bits can not set to 5 or 6\r
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return)\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialSetAttributes (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN UINT64 BaudRate,\r
+ IN UINT32 ReceiveFifoDepth,\r
+ IN UINT32 Timeout,\r
+ IN EFI_PARITY_TYPE Parity,\r
+ IN UINT8 DataBits,\r
+ IN EFI_STOP_BITS_TYPE StopBits\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SERIAL_DEV *SerialDevice;\r
+ UINT64 Divisor;\r
+ SERIAL_PORT_LCR Lcr;\r
+ UART_DEVICE_PATH *Uart;\r
+ EFI_TPL Tpl;\r
+\r
+ SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
+\r
+ //\r
+ // Check for default settings and fill in actual values.\r
+ //\r
+ if (BaudRate == 0) {\r
+ BaudRate = PcdGet64 (PcdUartDefaultBaudRate);\r
+ }\r
+\r
+ if (ReceiveFifoDepth == 0) {\r
+ ReceiveFifoDepth = SerialDevice->ReceiveFifoDepth;\r
+ }\r
+\r
+ if (Timeout == 0) {\r
+ Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;\r
+ }\r
+\r
+ if (Parity == DefaultParity) {\r
+ Parity = (EFI_PARITY_TYPE) PcdGet8 (PcdUartDefaultParity);\r
+ }\r
+\r
+ if (DataBits == 0) {\r
+ DataBits = PcdGet8 (PcdUartDefaultDataBits);\r
+ }\r
+\r
+ if (StopBits == DefaultStopBits) {\r
+ StopBits = (EFI_STOP_BITS_TYPE) PcdGet8 (PcdUartDefaultStopBits);\r
+ }\r
+\r
+ if (!VerifyUartParameters (SerialDevice->ClockRate, BaudRate, DataBits, Parity, StopBits, &Divisor, &BaudRate)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((ReceiveFifoDepth == 0) || (ReceiveFifoDepth > SerialDevice->ReceiveFifoDepth)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ SerialFlushTransmitFifo (SerialDevice);\r
+\r
+ //\r
+ // Put serial port on Divisor Latch Mode\r
+ //\r
+ Lcr.Data = READ_LCR (SerialDevice);\r
+ Lcr.Bits.DLab = 1;\r
+ WRITE_LCR (SerialDevice, Lcr.Data);\r
+\r
+ //\r
+ // Write the divisor to the serial port\r
+ //\r
+ WRITE_DLL (SerialDevice, (UINT8) Divisor);\r
+ WRITE_DLM (SerialDevice, (UINT8) ((UINT16) Divisor >> 8));\r
+\r
+ //\r
+ // Put serial port back in normal mode and set remaining attributes.\r
+ //\r
+ Lcr.Bits.DLab = 0;\r
+\r
+ switch (Parity) {\r
+ case NoParity:\r
+ Lcr.Bits.ParEn = 0;\r
+ Lcr.Bits.EvenPar = 0;\r
+ Lcr.Bits.SticPar = 0;\r
+ break;\r
+\r
+ case EvenParity:\r
+ Lcr.Bits.ParEn = 1;\r
+ Lcr.Bits.EvenPar = 1;\r
+ Lcr.Bits.SticPar = 0;\r
+ break;\r
+\r
+ case OddParity:\r
+ Lcr.Bits.ParEn = 1;\r
+ Lcr.Bits.EvenPar = 0;\r
+ Lcr.Bits.SticPar = 0;\r
+ break;\r
+\r
+ case SpaceParity:\r
+ Lcr.Bits.ParEn = 1;\r
+ Lcr.Bits.EvenPar = 1;\r
+ Lcr.Bits.SticPar = 1;\r
+ break;\r
+\r
+ case MarkParity:\r
+ Lcr.Bits.ParEn = 1;\r
+ Lcr.Bits.EvenPar = 0;\r
+ Lcr.Bits.SticPar = 1;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ switch (StopBits) {\r
+ case OneStopBit:\r
+ Lcr.Bits.StopB = 0;\r
+ break;\r
+\r
+ case OneFiveStopBits:\r
+ case TwoStopBits:\r
+ Lcr.Bits.StopB = 1;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ //\r
+ // DataBits\r
+ //\r
+ Lcr.Bits.SerialDB = (UINT8) ((DataBits - 5) & 0x03);\r
+ WRITE_LCR (SerialDevice, Lcr.Data);\r
+\r
+ //\r
+ // Set the Serial I/O mode\r
+ //\r
+ This->Mode->BaudRate = BaudRate;\r
+ This->Mode->ReceiveFifoDepth = ReceiveFifoDepth;\r
+ This->Mode->Timeout = Timeout;\r
+ This->Mode->Parity = Parity;\r
+ This->Mode->DataBits = DataBits;\r
+ This->Mode->StopBits = StopBits;\r
+\r
+ //\r
+ // See if Device Path Node has actually changed\r
+ //\r
+ if (SerialDevice->UartDevicePath.BaudRate == BaudRate &&\r
+ SerialDevice->UartDevicePath.DataBits == DataBits &&\r
+ SerialDevice->UartDevicePath.Parity == Parity &&\r
+ SerialDevice->UartDevicePath.StopBits == StopBits\r
+ ) {\r
+ gBS->RestoreTPL (Tpl);\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // Update the device path\r
+ //\r
+ SerialDevice->UartDevicePath.BaudRate = BaudRate;\r
+ SerialDevice->UartDevicePath.DataBits = DataBits;\r
+ SerialDevice->UartDevicePath.Parity = (UINT8) Parity;\r
+ SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits;\r
+\r
+ Status = EFI_SUCCESS;\r
+ if (SerialDevice->Handle != NULL) {\r
+\r
+ //\r
+ // Skip the optional Controller device path node\r
+ //\r
+ Uart = SkipControllerDevicePathNode (\r
+ (EFI_DEVICE_PATH_PROTOCOL *) (\r
+ (UINT8 *) SerialDevice->DevicePath + GetDevicePathSize (SerialDevice->ParentDevicePath) - END_DEVICE_PATH_LENGTH\r
+ ),\r
+ NULL,\r
+ NULL\r
+ );\r
+ CopyMem (Uart, &SerialDevice->UartDevicePath, sizeof (UART_DEVICE_PATH));\r
+ Status = gBS->ReinstallProtocolInterface (\r
+ SerialDevice->Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ SerialDevice->DevicePath,\r
+ SerialDevice->DevicePath\r
+ );\r
+ }\r
+\r
+ gBS->RestoreTPL (Tpl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set Control Bits.\r
+\r
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL\r
+ @param Control Control bits that can be settable\r
+\r
+ @retval EFI_SUCCESS New Control bits were set successfully\r
+ @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialSetControl (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN UINT32 Control\r
+ )\r
+{\r
+ SERIAL_DEV *SerialDevice;\r
+ SERIAL_PORT_MCR Mcr;\r
+ EFI_TPL Tpl;\r
+ UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // The control bits that can be set are :\r
+ // EFI_SERIAL_DATA_TERMINAL_READY: 0x0001 // WO\r
+ // EFI_SERIAL_REQUEST_TO_SEND: 0x0002 // WO\r
+ // EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000 // RW\r
+ // EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000 // RW\r
+ // EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE: 0x4000 // RW\r
+ //\r
+ SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
+\r
+ //\r
+ // first determine the parameter is invalid\r
+ //\r
+ if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |\r
+ EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |\r
+ EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ Mcr.Data = READ_MCR (SerialDevice);\r
+ Mcr.Bits.DtrC = 0;\r
+ Mcr.Bits.Rts = 0;\r
+ Mcr.Bits.Lme = 0;\r
+ SerialDevice->SoftwareLoopbackEnable = FALSE;\r
+ SerialDevice->HardwareFlowControl = FALSE;\r
+\r
+ if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {\r
+ Mcr.Bits.DtrC = 1;\r
+ }\r
+\r
+ if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {\r
+ Mcr.Bits.Rts = 1;\r
+ }\r
+\r
+ if ((Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) == EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {\r
+ Mcr.Bits.Lme = 1;\r
+ }\r
+\r
+ if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) == EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {\r
+ SerialDevice->HardwareFlowControl = TRUE;\r
+ }\r
+\r
+ WRITE_MCR (SerialDevice, Mcr.Data);\r
+\r
+ if ((Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) == EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {\r
+ SerialDevice->SoftwareLoopbackEnable = TRUE;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ if (SerialDevice->Handle != NULL) {\r
+ FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) (\r
+ (UINTN) SerialDevice->DevicePath\r
+ + GetDevicePathSize (SerialDevice->ParentDevicePath)\r
+ - END_DEVICE_PATH_LENGTH\r
+ + sizeof (UART_DEVICE_PATH)\r
+ );\r
+ if (IsUartFlowControlDevicePathNode (FlowControl) &&\r
+ ((BOOLEAN) (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) != SerialDevice->HardwareFlowControl)) {\r
+ //\r
+ // Flow Control setting is changed, need to reinstall device path protocol\r
+ //\r
+ WriteUnaligned32 (&FlowControl->FlowControlMap, SerialDevice->HardwareFlowControl ? UART_FLOW_CONTROL_HARDWARE : 0);\r
+ Status = gBS->ReinstallProtocolInterface (\r
+ SerialDevice->Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ SerialDevice->DevicePath,\r
+ SerialDevice->DevicePath\r
+ );\r
+ }\r
+ }\r
+\r
+ gBS->RestoreTPL (Tpl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get ControlBits.\r
+\r
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL\r
+ @param Control Control signals of the serial device\r
+\r
+ @retval EFI_SUCCESS Get Control signals successfully\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialGetControl (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ OUT UINT32 *Control\r
+ )\r
+{\r
+ SERIAL_DEV *SerialDevice;\r
+ SERIAL_PORT_MSR Msr;\r
+ SERIAL_PORT_MCR Mcr;\r
+ EFI_TPL Tpl;\r
+\r
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
+\r
+ *Control = 0;\r
+\r
+ //\r
+ // Read the Modem Status Register\r
+ //\r
+ Msr.Data = READ_MSR (SerialDevice);\r
+\r
+ if (Msr.Bits.Cts == 1) {\r
+ *Control |= EFI_SERIAL_CLEAR_TO_SEND;\r
+ }\r
+\r
+ if (Msr.Bits.Dsr == 1) {\r
+ *Control |= EFI_SERIAL_DATA_SET_READY;\r
+ }\r
+\r
+ if (Msr.Bits.Ri == 1) {\r
+ *Control |= EFI_SERIAL_RING_INDICATE;\r
+ }\r
+\r
+ if (Msr.Bits.Dcd == 1) {\r
+ *Control |= EFI_SERIAL_CARRIER_DETECT;\r
+ }\r
+ //\r
+ // Read the Modem Control Register\r
+ //\r
+ Mcr.Data = READ_MCR (SerialDevice);\r
+\r
+ if (Mcr.Bits.DtrC == 1) {\r
+ *Control |= EFI_SERIAL_DATA_TERMINAL_READY;\r
+ }\r
+\r
+ if (Mcr.Bits.Rts == 1) {\r
+ *Control |= EFI_SERIAL_REQUEST_TO_SEND;\r
+ }\r
+\r
+ if (Mcr.Bits.Lme == 1) {\r
+ *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;\r
+ }\r
+\r
+ if (SerialDevice->HardwareFlowControl) {\r
+ *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
+ }\r
+ //\r
+ // Update FIFO status\r
+ //\r
+ SerialReceiveTransmit (SerialDevice);\r
+\r
+ //\r
+ // See if the Transmit FIFO is empty\r
+ //\r
+ if (SerialFifoEmpty (&SerialDevice->Transmit)) {\r
+ *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;\r
+ }\r
+\r
+ //\r
+ // See if the Receive FIFO is empty.\r
+ //\r
+ if (SerialFifoEmpty (&SerialDevice->Receive)) {\r
+ *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;\r
+ }\r
+\r
+ if (SerialDevice->SoftwareLoopbackEnable) {\r
+ *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;\r
+ }\r
+\r
+ gBS->RestoreTPL (Tpl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Write the specified number of bytes to serial device.\r
+\r
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL\r
+ @param BufferSize On input the size of 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 were written successfully\r
+ @retval EFI_DEVICE_ERROR The device reported an error\r
+ @retval EFI_TIMEOUT The write operation was stopped due to timeout\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialWrite (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN OUT UINTN *BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ SERIAL_DEV *SerialDevice;\r
+ UINT8 *CharBuffer;\r
+ UINT32 Index;\r
+ UINTN Elapsed;\r
+ UINTN ActualWrite;\r
+ EFI_TPL Tpl;\r
+ UINTN Timeout;\r
+ UINTN BitsPerCharacter;\r
+\r
+ SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
+ Elapsed = 0;\r
+ ActualWrite = 0;\r
+\r
+ if (*BufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (Buffer == NULL) {\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_ERROR_CODE,\r
+ EFI_P_EC_OUTPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,\r
+ SerialDevice->DevicePath\r
+ );\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ CharBuffer = (UINT8 *) Buffer;\r
+\r
+ //\r
+ // Compute the number of bits in a single character. This is a start bit,\r
+ // followed by the number of data bits, followed by the number of stop bits.\r
+ // The number of stop bits is specified by an enumeration that includes\r
+ // support for 1.5 stop bits. Treat 1.5 stop bits as 2 stop bits.\r
+ //\r
+ BitsPerCharacter =\r
+ 1 +\r
+ This->Mode->DataBits +\r
+ ((This->Mode->StopBits == TwoStopBits) ? 2 : This->Mode->StopBits);\r
+\r
+ //\r
+ // Compute the timeout in microseconds to wait for a single byte to be\r
+ // transmitted. The Mode structure contans a Timeout field that is the\r
+ // maximum time to transmit or receive a character. However, many UARTs\r
+ // have a FIFO for transmits, so the time required to add one new character\r
+ // to the transmit FIFO may be the time required to flush a full FIFO. If\r
+ // the Timeout in the Mode structure is smaller than the time required to\r
+ // flush a full FIFO at the current baud rate, then use a timeout value that\r
+ // is required to flush a full transmit FIFO.\r
+ //\r
+ Timeout = MAX (\r
+ This->Mode->Timeout,\r
+ (UINTN)DivU64x64Remainder (\r
+ BitsPerCharacter * (SerialDevice->TransmitFifoDepth + 1) * 1000000,\r
+ This->Mode->BaudRate,\r
+ NULL\r
+ )\r
+ );\r
+ \r
+ for (Index = 0; Index < *BufferSize; Index++) {\r
+ SerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]);\r
+\r
+ while (SerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || !SerialFifoEmpty (&SerialDevice->Transmit)) {\r
+ //\r
+ // Unsuccessful write so check if timeout has expired, if not,\r
+ // stall for a bit, increment time elapsed, and try again\r
+ //\r
+ if (Elapsed >= Timeout) {\r
+ *BufferSize = ActualWrite;\r
+ gBS->RestoreTPL (Tpl);\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ gBS->Stall (TIMEOUT_STALL_INTERVAL);\r
+\r
+ Elapsed += TIMEOUT_STALL_INTERVAL;\r
+ }\r
+\r
+ ActualWrite++;\r
+ //\r
+ // Successful write so reset timeout\r
+ //\r
+ Elapsed = 0;\r
+ }\r
+\r
+ gBS->RestoreTPL (Tpl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read the specified number of bytes from serial device.\r
+\r
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL\r
+ @param BufferSize On input the size of 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 were read successfully\r
+ @retval EFI_DEVICE_ERROR The device reported an error\r
+ @retval EFI_TIMEOUT The read operation was stopped due to timeout\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialRead (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ SERIAL_DEV *SerialDevice;\r
+ UINT32 Index;\r
+ UINT8 *CharBuffer;\r
+ UINTN Elapsed;\r
+ EFI_STATUS Status;\r
+ EFI_TPL Tpl;\r
+\r
+ SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
+ Elapsed = 0;\r
+\r
+ if (*BufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ Status = SerialReceiveTransmit (SerialDevice);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ *BufferSize = 0;\r
+\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_ERROR_CODE,\r
+ EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,\r
+ SerialDevice->DevicePath\r
+ );\r
+\r
+ gBS->RestoreTPL (Tpl);\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ CharBuffer = (UINT8 *) Buffer;\r
+ for (Index = 0; Index < *BufferSize; Index++) {\r
+ while (SerialFifoRemove (&SerialDevice->Receive, &(CharBuffer[Index])) != EFI_SUCCESS) {\r
+ //\r
+ // Unsuccessful read so check if timeout has expired, if not,\r
+ // stall for a bit, increment time elapsed, and try again\r
+ // Need this time out to get conspliter to work.\r
+ //\r
+ if (Elapsed >= This->Mode->Timeout) {\r
+ *BufferSize = Index;\r
+ gBS->RestoreTPL (Tpl);\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ gBS->Stall (TIMEOUT_STALL_INTERVAL);\r
+ Elapsed += TIMEOUT_STALL_INTERVAL;\r
+\r
+ Status = SerialReceiveTransmit (SerialDevice);\r
+ if (Status == EFI_DEVICE_ERROR) {\r
+ *BufferSize = Index;\r
+ gBS->RestoreTPL (Tpl);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+ //\r
+ // Successful read so reset timeout\r
+ //\r
+ Elapsed = 0;\r
+ }\r
+\r
+ SerialReceiveTransmit (SerialDevice);\r
+\r
+ gBS->RestoreTPL (Tpl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Use scratchpad register to test if this serial port is present.\r
+\r
+ @param SerialDevice Pointer to serial device structure\r
+\r
+ @return if this serial port is present\r
+**/\r
+BOOLEAN\r
+SerialPresent (\r
+ IN SERIAL_DEV *SerialDevice\r
+ )\r
+\r
+{\r
+ UINT8 Temp;\r
+ BOOLEAN Status;\r
+\r
+ Status = TRUE;\r
+\r
+ //\r
+ // Save SCR reg\r
+ //\r
+ Temp = READ_SCR (SerialDevice);\r
+ WRITE_SCR (SerialDevice, 0xAA);\r
+\r
+ if (READ_SCR (SerialDevice) != 0xAA) {\r
+ Status = FALSE;\r
+ }\r
+\r
+ WRITE_SCR (SerialDevice, 0x55);\r
+\r
+ if (READ_SCR (SerialDevice) != 0x55) {\r
+ Status = FALSE;\r
+ }\r
+ //\r
+ // Restore SCR\r
+ //\r
+ WRITE_SCR (SerialDevice, Temp);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read serial port.\r
+\r
+ @param SerialDev Pointer to serial device\r
+ @param Offset Offset in register group\r
+\r
+ @return Data read from serial port\r
+\r
+**/\r
+UINT8\r
+SerialReadRegister (\r
+ IN SERIAL_DEV *SerialDev,\r
+ IN UINT32 Offset\r
+ )\r
+{\r
+ UINT8 Data;\r
+ EFI_STATUS Status;\r
+\r
+ if (SerialDev->PciDeviceInfo == NULL) {\r
+ return IoRead8 ((UINTN) SerialDev->BaseAddress + Offset * SerialDev->RegisterStride);\r
+ } else {\r
+ if (SerialDev->MmioAccess) {\r
+ Status = SerialDev->PciDeviceInfo->PciIo->Mem.Read (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);\r
+ } else {\r
+ Status = SerialDev->PciDeviceInfo->PciIo->Io.Read (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);\r
+ }\r
+ ASSERT_EFI_ERROR (Status);\r
+ return Data;\r
+ }\r
+}\r
+\r
+/**\r
+ Write serial port.\r
+\r
+ @param SerialDev Pointer to serial device\r
+ @param Offset Offset in register group\r
+ @param Data data which is to be written to some serial port register\r
+**/\r
+VOID\r
+SerialWriteRegister (\r
+ IN SERIAL_DEV *SerialDev,\r
+ IN UINT32 Offset,\r
+ IN UINT8 Data\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (SerialDev->PciDeviceInfo == NULL) {\r
+ IoWrite8 ((UINTN) SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, Data);\r
+ } else {\r
+ if (SerialDev->MmioAccess) {\r
+ Status = SerialDev->PciDeviceInfo->PciIo->Mem.Write (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);\r
+ } else {\r
+ Status = SerialDev->PciDeviceInfo->PciIo->Io.Write (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);\r
+ }\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+}\r
# @Prompt Enable S3 performance data support.\r
gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwarePerformanceDataTableS3Support|TRUE|BOOLEAN|0x00010064\r
\r
+ ## Indicates if Serial device uses half hand shake.<BR><BR>\r
+ # TRUE - Serial device uses half hand shake.<BR>\r
+ # FALSE - Serial device doesn't use half hand shake.<BR>\r
+ # @Prompt Enable Serial device Half Hand Shake\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHalfHandshake|FALSE|BOOLEAN|0x00010073\r
+\r
[PcdsFeatureFlag.IA32, PcdsFeatureFlag.X64]\r
## Indicates if DxeIpl should switch to long mode to enter DXE phase.\r
# It is assumed that 64-bit DxeCore is built in firmware if it is true; otherwise 32-bit DxeCore\r
# @Prompt Pci Serial Device Info\r
gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo|{0xFF}|VOID*|0x00010067\r
\r
+ ## PCI Serial Parameters. It is an array of VendorID, DeviceID, ClockRate, Offset,\r
+ # BarIndex, RegisterStride, ReceiveFifoDepth, TransmitFifoDepth information that \r
+ # describes the parameters of special PCI serial devices.\r
+ # Each array entry is 24-byte in length. The array is terminated\r
+ # by an array entry with a PCI Vendor ID of 0xFFFF. If a platform only contains a\r
+ # standard 16550 PCI serial device whose class code is 7/0/2, the value is 0xFFFF.\r
+ # The C style structure is defined as below:\r
+ # typedef struct {\r
+ # UINT16 VendorId; ///< Vendor ID to match the PCI device. The value 0xFFFF terminates the list of entries.\r
+ # UINT16 DeviceId; ///< Device ID to match the PCI device\r
+ # UINT32 ClockRate; ///< UART clock rate. Set to 0 for default clock rate of 1843200 Hz\r
+ # UINT64 Offset; ///< The byte offset into to the BAR\r
+ # UINT8 BarIndex; ///< Which BAR to get the UART base address\r
+ # UINT8 RegisterStride; ///< UART register stride in bytes. Set to 0 for default register stride of 1 byte.\r
+ # UINT16 ReceiveFifoDepth; ///< UART receive FIFO depth in bytes. Set to 0 for a default FIFO depth of 16 bytes.\r
+ # UINT16 TransmitFifoDepth; ///< UART transmit FIFO depth in bytes. Set to 0 for a default FIFO depth of 16 bytes.\r
+ # UINT8 Reserved[2];\r
+ # } PCI_SERIAL_PARAMETER;\r
+ # It contains zero or more instances of the above structure.\r
+ # For example, if a PCI device contains two UARTs, PcdPciSerialParameters needs\r
+ # to contain two instances of the above structure, with the VendorId and DeviceId\r
+ # equals to the Device ID and Vendor ID of the device; If the PCI device uses the\r
+ # first two BARs to support two UARTs, BarIndex of first instance equals to 0 and\r
+ # BarIndex of second one equals to 1; If the PCI device uses the first BAR to\r
+ # support both UARTs, BarIndex of both instance equals to 0, Offset of first\r
+ # instance equals to 0 and Offset of second one equals to a value bigger than or\r
+ # equal to 8.\r
+ # For certain UART whose register needs to be accessed in DWORD aligned address,\r
+ # RegisterStride equals to 4.\r
+ # @Prompt Pci Serial Parameters\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPciSerialParameters|{0xFF, 0xFF}|VOID*|0x00010071\r
+\r
## Serial Port Extended Transmit FIFO Size. The default is 64 bytes. \r
# @Prompt Serial Port Extended Transmit FIFO Size in Bytes\r
gEfiMdeModulePkgTokenSpaceGuid.PcdSerialExtendedTxFifoSize|64|UINT32|0x00010068\r
MdeModulePkg/Application/HelloWorld/HelloWorld.inf\r
MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf\r
\r
+ MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf\r
MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf\r
MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf\r
MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf\r