]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg: Add PciSioSerialDxe driver
authorRuiyu Ni <ruiyu.ni@intel.com>
Thu, 10 Dec 2015 02:47:16 +0000 (02:47 +0000)
committerniruiyu <niruiyu@Edk2>
Thu, 10 Dec 2015 02:47:16 +0000 (02:47 +0000)
PciSioSerialDxe driver can manages UARTs on a SIO chip or a PCI/PCIE
card.
It manages the SIO instance whose last device path node is a ACPI
device path and the HID in the ACPI device path node equals to
EISA_PNP_ID (0x501).
It also manages the PCI IO instance whose class code is 7/0/2 (16550
UART). But when proper value is set to PcdPciSerialParameters, the
driver can also manage non-standard PCI serial cards by matching
the Vendor ID and Device ID specified in PcdPciSerialParameters.
The PCI BAR index, IO/MMIO offset, register stride, clock rate can
also be specified through the same PCD.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Reviewed-by: Feng Tian <feng.tian@intel.com>
Reviewed-by: Michael Kinney <michael.d.kinney@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19179 6f19259b-4bc3-4df7-8a09-765794883524

MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf [new file with mode: 0644]
MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni [new file with mode: 0644]
MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni [new file with mode: 0644]
MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c [new file with mode: 0644]
MdeModulePkg/MdeModulePkg.dec
MdeModulePkg/MdeModulePkg.dsc

diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..994dc84
--- /dev/null
@@ -0,0 +1,288 @@
+/** @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
diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf
new file mode 100644 (file)
index 0000000..03fddfe
--- /dev/null
@@ -0,0 +1,81 @@
+## @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
diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni
new file mode 100644 (file)
index 0000000..617f583
Binary files /dev/null and b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni differ
diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni
new file mode 100644 (file)
index 0000000..935bdba
Binary files /dev/null and b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni differ
diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c
new file mode 100644 (file)
index 0000000..86e75a4
--- /dev/null
@@ -0,0 +1,1242 @@
+/** @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
diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h
new file mode 100644 (file)
index 0000000..f147e69
--- /dev/null
@@ -0,0 +1,789 @@
+/** @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
diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c
new file mode 100644 (file)
index 0000000..f1870f3
--- /dev/null
@@ -0,0 +1,1320 @@
+/** @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
index 270277ee695fb3ce53cefc5f9ed112add7f31c10..5ec37c5a7d056d5809d5e8c4e1e22f07ca217909 100644 (file)
   # @Prompt Enable S3 performance data support.\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwarePerformanceDataTableS3Support|TRUE|BOOLEAN|0x00010064\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
 [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
   # @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
   ## 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
index 06e1093d0ab5c8843252f21bc4a92e6c4ac7da9e..b31c02e19e9fb5f4fb79237c06f769faec94e80d 100644 (file)
   MdeModulePkg/Application/HelloWorld/HelloWorld.inf\r
   MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf\r
 \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
   MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf\r
   MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf\r
   MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf\r