Suggest to use UINT64 for Offset field to be consistent with PciIo protocol 
definition.

Others look good to me

Reviewed-by: Feng Tian <feng.t...@intel.com>

Thanks
Feng

-----Original Message-----
From: edk2-devel [mailto:edk2-devel-boun...@lists.01.org] On Behalf Of Ni, Ruiyu
Sent: Monday, November 30, 2015 10:12
To: Kinney, Michael D
Cc: edk2-devel@lists.01.org
Subject: Re: [edk2] [Patch 1/2] MdeModulePkg: Add PciSioSerialDxe driver

Mike,
Could you please review whether the PCD structure defined as below is good?

+#pragma pack(1)
+///
+/// PcdPciSerialParameters contains zero or more instances of the below 
structure.
+/// If a PCI device contains multiple UARTs, PcdPciSerialParameters needs to 
contain
+/// two instances of the below structure, with the VendorId and DeviceId 
equals to the
+/// device ID and vendor ID of the device. If the PCI device uses the first 
two BARs
+/// to support multiple UARTs, BarIndex of first instance equals to 0 and 
BarIndex of
+/// second one equals to 1; if the PCI device uses the first BAR to support 
multiple
+/// UARTs, BarIndex of both instance equals to 0 and Offset of first instance 
equals
+/// to 0 while Offset of second one equals to some value bigger or equal to 8.
+/// For certain UART whose register needs to be accessed in DWORD aligned 
address,
+/// RegisterStride equals to 4.
+///
+typedef struct {
+  UINT16  VendorId;       ///< Vendor ID to match the PCI device, 0xFFFF 
terminates the entries
+  UINT16  DeviceId;       ///< Device ID to match the PCI device
+  UINT8   BarIndex;       ///< Which BAR to get the UART base address
+  UINT16  Offset;         ///< The offset to the BAR 
+  UINT8   RegisterStride; ///< UART register stride, 0 to use 1 as register 
stride
+  UINT32  ClockRate;      ///< UART clock rate, 0 to use default clock rate 
1843200
+} PCI_SERIAL_PARAMETER;
+#pragma pack()

Regards,
Ray

-----Original Message-----
From: Ni, Ruiyu 
Sent: Wednesday, November 25, 2015 10:30 PM
To: edk2-devel@lists.01.org
Cc: Ni, Ruiyu <ruiyu...@intel.com>; Tian, Feng <feng.t...@intel.com>; Kinney, 
Michael D <michael.d.kin...@intel.com>
Subject: [Patch 1/2] MdeModulePkg: Add PciSioSerialDxe driver

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...@intel.com>
Cc: Feng Tian <feng.t...@intel.com>
Cc: Michael Kinney <michael.d.kin...@intel.com>
---
 .../Bus/Pci/PciSioSerialDxe/ComponentName.c        |  288 +++++
 .../Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf    |   81 ++
 .../Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni    |  Bin 0 -> 1940 bytes
 .../Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni   |  Bin 0 -> 1380 bytes
 MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c      | 1206 +++++++++++++++++++
 MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h      |  787 +++++++++++++
 MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c    | 1243 ++++++++++++++++++++
 MdeModulePkg/MdeModulePkg.dec                      |   34 +
 8 files changed, 3639 insertions(+)
 create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c
 create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf
 create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni
 create mode 100644 
MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni
 create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c
 create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h
 create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c

diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c 
b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c
new file mode 100644
index 0000000..994dc84
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c
@@ -0,0 +1,288 @@
+/** @file
+  UEFI Component Name and Name2 protocol for Isa serial driver.
+
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD 
License
+which accompanies this distribution.  The full text of the license may be 
found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Serial.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  
gPciSioSerialComponentName = {
+  SerialComponentNameGetDriverName,
+  SerialComponentNameGetControllerName,
+  "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL 
gPciSioSerialComponentName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SerialComponentNameGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) 
SerialComponentNameGetControllerName,
+  "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE 
mSerialDriverNameTable[] = {
+  {
+    "eng;en",
+    L"PCI SIO Serial Driver"
+  },
+  {
+    NULL,
+    NULL
+  }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 mSioSerialPortName[] = L"SIO Serial Port 
#%d";
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 mPciSerialPortName[] = L"PCI Serial Port 
#%d";
+
+/**
+  Retrieves a Unicode string that is the user readable name of the driver.
+
+  This function retrieves the user readable name of a driver in the form of a
+  Unicode string. If the driver specified by This has a user readable name in
+  the language specified by Language, then a pointer to the driver name is
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+  by This does not support the language specified by Language,
+  then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL 
or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language. This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified
+                                in RFC 4646 or ISO 639-2 language code format.
+
+  @param  DriverName[out]       A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                driver specified by This in the language
+                                specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
+                                This and the language specified by Language was
+                                returned in DriverName.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mSerialDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &gPciSioSerialComponentName)
+           );
+}
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by a driver.
+
+  This function retrieves the user readable name of the controller specified by
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the
+  driver specified by This has a user readable name in the language specified 
by
+  Language, then a pointer to the controller name is returned in 
ControllerName,
+  and EFI_SUCCESS is returned.  If the driver specified by This is not 
currently
+  managing the controller specified by ControllerHandle and ChildHandle,
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL 
or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  ControllerHandle[in]  The handle of a controller that the driver
+                                specified by This is managing.  This handle
+                                specifies the controller whose name is to be
+                                returned.
+
+  @param  ChildHandle[in]       The handle of the child controller to retrieve
+                                the name of.  This is an optional parameter 
that
+                                may be NULL.  It will be NULL for device
+                                drivers.  It will also be NULL for a bus 
drivers
+                                that wish to retrieve the name of the bus
+                                controller.  It will not be NULL for a bus
+                                driver that wishes to retrieve the name of a
+                                child controller.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language.  This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified in
+                                RFC 4646 or ISO 639-2 language code format.
+
+  @param  ControllerName[out]   A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                controller specified by ControllerHandle and
+                                ChildHandle in the language specified by
+                                Language from the point of view of the driver
+                                specified by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user readable name 
in
+                                the language specified by Language for the
+                                driver specified by This was returned in
+                                DriverName.
+
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+                                EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
+                                managing the controller specified by
+                                ControllerHandle and ChildHandle.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        
OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  )
+{
+  EFI_STATUS                Status;
+  EFI_SERIAL_IO_PROTOCOL    *SerialIo;
+  SERIAL_DEV                *SerialDevice;
+  EFI_UNICODE_STRING_TABLE  *ControllerNameTable;
+  EFI_GUID                  *IoProtocolGuid;
+
+  //
+  // Make sure this driver is currently managing ControllerHandle
+  //
+  IoProtocolGuid = &gEfiSioProtocolGuid;
+  Status = EfiTestManagedDevice (
+             ControllerHandle,
+             gSerialControllerDriver.DriverBindingHandle,
+             IoProtocolGuid
+             );
+  if (EFI_ERROR (Status)) {
+    IoProtocolGuid = &gEfiPciIoProtocolGuid;
+    Status = EfiTestManagedDevice (
+               ControllerHandle,
+               gSerialControllerDriver.DriverBindingHandle,
+               IoProtocolGuid
+               );
+  }
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  ControllerNameTable = NULL;
+  if (ChildHandle != NULL) {
+    Status = EfiTestChildHandle (
+               ControllerHandle,
+               ChildHandle,
+               IoProtocolGuid
+               );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    //
+    // Get the Serial I/O Protocol from the child handle
+    //
+    Status = gBS->OpenProtocol (
+                    ChildHandle,
+                    &gEfiSerialIoProtocolGuid,
+                    (VOID **) &SerialIo,
+                    gSerialControllerDriver.DriverBindingHandle,
+                    ChildHandle,
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                    );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    //
+    // Get the Serial Controller's Device structure
+    //
+    SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo);
+    ControllerNameTable = SerialDevice->ControllerNameTable;
+  }
+
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           ControllerNameTable,
+           ControllerName,
+           (BOOLEAN)(This == &gPciSioSerialComponentName)
+           );
+}
+
+/**
+  Add the ISO639-2 and RFC4646 component name both for the Serial IO device
+
+  @param SerialDevice     A pointer to the SERIAL_DEV instance.
+  @param Instance         Instance ID for the serial device.
+**/
+VOID
+AddName (
+  IN  SERIAL_DEV                               *SerialDevice,
+  IN  UINT32                                   Instance
+  )
+{
+  CHAR16                                       
SerialPortName[SERIAL_PORT_NAME_LEN];
+  UnicodeSPrint (
+    SerialPortName,
+    sizeof (SerialPortName),
+    (SerialDevice->PciDeviceInfo != NULL) ? PCI_SERIAL_PORT_NAME : 
SIO_SERIAL_PORT_NAME,
+    Instance
+    );
+  AddUnicodeString2 (
+    "eng",
+    gPciSioSerialComponentName.SupportedLanguages,
+    &SerialDevice->ControllerNameTable,
+    SerialPortName,
+    TRUE
+    );
+  AddUnicodeString2 (
+    "en",
+    gPciSioSerialComponentName2.SupportedLanguages,
+    &SerialDevice->ControllerNameTable,
+    SerialPortName,
+    FALSE
+    );
+
+}
diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf 
b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf
new file mode 100644
index 0000000..af92e02
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf
@@ -0,0 +1,81 @@
+## @file
+# Serial driver for standard UARTS on a SIO chip or PCI/PCIE card.
+# 
+# Produces the Serial I/O protocol for standard UARTS using Super I/O or PCI 
I/O.
+#
+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD 
License
+# which accompanies this distribution. The full text of the license may be 
found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PciSioSerialDxe
+  MODULE_UNI_FILE                = PciSioSerialDxe.uni
+  FILE_GUID                      = E2775B47-D453-4EE3-ADA7-391A1B05AC17
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = InitializePciSioSerial
+
+#
+# The following information is for reference only and not required by the 
build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+#  DRIVER_BINDING                =  gSerialControllerDriver                    
  
+#  COMPONENT_NAME                =  gPciSioSerialComponentName                 
     
+#  COMPONENT_NAME2               =  gPciSioSerialComponentName2
+#
+
+[Sources]
+  ComponentName.c
+  SerialIo.c
+  Serial.h
+  Serial.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  PcdLib
+  ReportStatusCodeLib
+  UefiBootServicesTableLib
+  MemoryAllocationLib
+  BaseMemoryLib
+  DevicePathLib
+  UefiLib
+  UefiDriverEntryPoint
+  DebugLib
+  IoLib
+
+[Guids]
+  gEfiUartDevicePathGuid                        ## SOMETIMES_CONSUMES   ## GUID
+
+[Protocols]
+  gEfiSioProtocolGuid                           ## TO_START
+  gEfiDevicePathProtocolGuid                    ## TO_START
+  gEfiPciIoProtocolGuid                         ## TO_START
+  gEfiSerialIoProtocolGuid                      ## BY_START
+  gEfiDevicePathProtocolGuid                    ## BY_START
+
+[FeaturePcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHalfHandshake|FALSE   ## CONSUMES
+
+[Pcd]
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate|115200    ## CONSUMES
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits|8         ## CONSUMES
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity|1           ## CONSUMES
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits|1         ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|1843200 ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdPciSerialParameters     ## CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  PciSioSerialDxeExtra.uni
diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni 
b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni
new file mode 100644
index 
0000000000000000000000000000000000000000..44ff6ef58285c0430c97e863d0daf9bbf39a9e66
GIT binary patch
literal 1940
zcmd6o-D?w35XI+N@PD|ZFDh-Kf(RmF+OE2&-H;EePqJ;=W}$7$CaLzHSAS<VyEh3D
z`=*5ZHFxfrbI;7({QB9kjs@Bie!<?_xfOP4XZFw@VAbA$Rf#pn9&GIMTek(gr>uj`
zY|j2QyE*GImXUR>Z$nN8e6Hzp+Q3rF7*A~i;*Ia=e9sQp=`6>@Ju0Mj!z4255o1b}
z1vqEK4n&_Y+vF-lMZ0nTIcH93y2br?FTgI~e&NUqaHK?Vroyf6UU9Fj+xQ;fd1H5+
zEx?+<HrOM$JZ5}uPx-xMwzph8vlq6@JSFm+h~g`R5)Ab@)`Ho!wb|*iFOP^VJxbR_
zY?Y}op0916e7xDB=FoGYQ<Y8^9^;C2mC>kf4reKNg{SuJ8g;ImRjiX)6Gtdw6JS|z
z`iyfk=M?dEdh9+qd~^IR=}+i&ZovudO8Gj^(xrrlSl2AYOrAxfk9MczI-c970uNb#
zTH_Kc>$_{A>J;w!Z3|)wQ5*`NDV8c<+MmF4H7`<C?9Z`R84~9o_-t}o*ClYP9AyKD
z)%odC0Wq4d=&CxJlZjXUPE}!*w(>7s={C17skqLD_A@LeFdtKM>(SewOlVP&I2+mr
zOW@U`jxu{s-?h)IQ-9-!J`S;_RN9D_pSaQ^J7P?*2W%BW%tA_KCwL4TIb)`ZR^MVA
zEYVwx`@UAJ-4%AnL=$S}5rZA$)puq`*i%r2k$Ln!D{+@iF^BldM^P)Uclav$SH_R*
zh`C;3vW!yQBC#(GPDD@9qDNgR<{|H`)~z0ce_=armrZS_sh;{9BmKUClz}k<En(H=
z?gN-g?*qp0$KMXw)N8n)0&;rQk7{BMEHQ1-$2a;fzU8gv{`b4PDrdm0RaLzvTiX=)
M``!QVe~qZjZ@CO8UH||9

literal 0
HcmV?d00001

diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni 
b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni
new file mode 100644
index 
0000000000000000000000000000000000000000..1de340ac907d59af1d83c86f8a04f239742af182
GIT binary patch
literal 1380
zcmZXUTW`}q5QXO%iT|()FM!&Fi+Di@ku(M@N*(1Q;3;x0O)ce8ISDlUc;GwZ*lvm<
z@9fUboH=`THh=%LtYv}kIlo{Z?AkJ0+T0%7BfQ${*%aS^Z^JmZoLNdt*X~#ayTm_r
zPiDXI%<v6t=W%OW*p_u_YxiFeyJm0hV_BoL!L)yC2hUyD4Uxf~g8mHq%3jz@d(G^;
zTD`F|=J648$y^9I7#dUZ#d>W`cG_@Og!mWOVwS^Y%a_|v=ian;*0H|5uN0`+4Plh|
zd2Wf{fT9{JP|EY|h>#{JoTo&rV4}SPdD0@_5vy9oZB<8EViRDQku8nHOnR31%AR>l
z3g48tCF6uqd3!Rnn=>z&6tz|-w;*PU%qo4P#D=@C^E%vNm-Xcdms*QouEmt`|I=o0
z5TZB~da2fywX~nW^Zva^Rk6RuU)+#5-x2eW)2S|nmItCH$NbGv0WsR$(^Y-6<0jsE
zN2|jMZ55xp(oIgEb3d&I+HdhpU_PVgPOCRTx#24nDQ&Q!eYOZzJ-R5dPmFE*$~s2T
zfTprTyfJ+?Vivj1BfG*z_-lmv4r2N`B4Xgk2{ZMx#s*fnLTz9>zSioj;uh>1`{I>&
zMXlRZ60<A(F{r{wyn3INxXY)SL!uO;szuaCVwL#=`-L4b*E@`kRf<zY_PxTX(POme
z(N(J1<z1G#l{WZ4QOo`EJ*oPpct3@9<D<GgQ2Nyg#$YF)j=+y>3@<6KyC{(KR)n(0
yF1%;d2j|3#pJE!|UcgQNU^;PNPf88lQ@>j2y!RgOa!OU`dT;ALBnL%U<@XPs4%3VP

literal 0
HcmV?d00001

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

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to