1a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni/** @file
2a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Serial driver for PCI or SIO UARTS.
3a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
4a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiCopyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
5a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiThis program and the accompanying materials
6a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Niare licensed and made available under the terms and conditions of the BSD License
7a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Niwhich accompanies this distribution.  The full text of the license may be found at
8a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Nihttp://opensource.org/licenses/bsd-license.php
9a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
10a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiTHE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiWITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
13a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni**/
14a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
15a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni#include "Serial.h"
16a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
17a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni//
18a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni// ISA Serial Driver Global Variables
19a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni//
20a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
21a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiEFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = {
22a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SerialControllerDriverSupported,
23a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SerialControllerDriverStart,
24a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SerialControllerDriverStop,
25a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  0xa,
26a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  NULL,
27a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  NULL
28a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni};
29a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
30a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiCONTROLLER_DEVICE_PATH mControllerDevicePathTemplate = {
31a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  {
32a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    HARDWARE_DEVICE_PATH,
33a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    HW_CONTROLLER_DP,
3483809dc0186eea34a9b0db6df306abe9e1c7776bMichael Kinney    {
3583809dc0186eea34a9b0db6df306abe9e1c7776bMichael Kinney      (UINT8) (sizeof (CONTROLLER_DEVICE_PATH)),
3683809dc0186eea34a9b0db6df306abe9e1c7776bMichael Kinney      (UINT8) ((sizeof (CONTROLLER_DEVICE_PATH)) >> 8)
3783809dc0186eea34a9b0db6df306abe9e1c7776bMichael Kinney    }
38a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  },
39a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  0
40a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni};
41a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
42a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiSERIAL_DEV  gSerialDevTemplate = {
43a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SERIAL_DEV_SIGNATURE,
44a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  NULL,
45a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  {
46a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    SERIAL_IO_INTERFACE_REVISION,
47a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    SerialReset,
48a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    SerialSetAttributes,
49a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    SerialSetControl,
50a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    SerialGetControl,
51a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    SerialWrite,
52a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    SerialRead,
53a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    NULL
54a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  },                                       // SerialIo
55a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  {
56a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    SERIAL_PORT_SUPPORT_CONTROL_MASK,
57a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    SERIAL_PORT_DEFAULT_TIMEOUT,
58a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    0,
59a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    16,
60a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    0,
61a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    0,
62a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    0
63a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  },                                       // SerialMode
64a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  NULL,                                    // DevicePath
65a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  NULL,                                    // ParentDevicePath
66a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  {
67a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    {
68a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      MESSAGING_DEVICE_PATH,
69a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      MSG_UART_DP,
70a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      {
71a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        (UINT8) (sizeof (UART_DEVICE_PATH)),
72a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)
73a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      }
74a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    },
75a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    0, 0, 0, 0, 0
76a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  },                                       // UartDevicePath
77a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  0,                                       // BaseAddress
78a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  FALSE,                                   // MmioAccess
79a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  1,                                       // RegisterStride
80a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  0,                                       // ClockRate
81a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  16,                                      // ReceiveFifoDepth
82a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  { 0, 0 },                                // Receive;
83a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  16,                                      // TransmitFifoDepth
84a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  { 0, 0 },                                // Transmit;
85a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  FALSE,                                   // SoftwareLoopbackEnable;
86a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  FALSE,                                   // HardwareFlowControl;
87a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  NULL,                                    // *ControllerNameTable;
88a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  FALSE,                                   // ContainsControllerNode;
89a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  0,                                       // Instance;
90a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  NULL                                     // *PciDeviceInfo;
91a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni};
92a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
93a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni/**
94a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Check the device path node whether it's the Flow Control node or not.
95a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
96a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param[in] FlowControl    The device path node to be checked.
97a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
98a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @retval TRUE              It's the Flow Control node.
99a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @retval FALSE             It's not.
100a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
101a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni**/
102a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiBOOLEAN
103a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiIsUartFlowControlDevicePathNode (
104a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl
105a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  )
106a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni{
107a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  return (BOOLEAN) (
108a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) &&
109a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) &&
110a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid))
111a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           );
112a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni}
113a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
114a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni/**
115a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  The user Entry Point for module PciSioSerial. The user code starts with this function.
116a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
117a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
118a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param[in] SystemTable    A pointer to the EFI System Table.
119a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
120a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @retval EFI_SUCCESS       The entry point is executed successfully.
121a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @retval other             Some error occurs when executing this entry point.
122a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
123a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni**/
124a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiEFI_STATUS
125a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiEFIAPI
126a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiInitializePciSioSerial (
127a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN EFI_HANDLE           ImageHandle,
128a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN EFI_SYSTEM_TABLE     *SystemTable
129a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  )
130a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni{
131a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_STATUS              Status;
132a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
133a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
134a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Install driver model protocol(s).
135a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
136a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Status = EfiLibInstallDriverBindingComponentName2 (
137a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni             ImageHandle,
138a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni             SystemTable,
139a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni             &gSerialControllerDriver,
140a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni             ImageHandle,
141a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni             &gPciSioSerialComponentName,
142a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni             &gPciSioSerialComponentName2
143a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni             );
144a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  ASSERT_EFI_ERROR (Status);
145a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
146a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
147a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Initialize UART default setting in gSerialDevTempate
148a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
149a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  gSerialDevTemplate.SerialMode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
150a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  gSerialDevTemplate.SerialMode.DataBits = PcdGet8 (PcdUartDefaultDataBits);
151a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  gSerialDevTemplate.SerialMode.Parity   = PcdGet8 (PcdUartDefaultParity);
152a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  gSerialDevTemplate.SerialMode.StopBits = PcdGet8 (PcdUartDefaultStopBits);
153a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  gSerialDevTemplate.UartDevicePath.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
154a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  gSerialDevTemplate.UartDevicePath.DataBits = PcdGet8 (PcdUartDefaultDataBits);
155a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  gSerialDevTemplate.UartDevicePath.Parity   = PcdGet8 (PcdUartDefaultParity);
156a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  gSerialDevTemplate.UartDevicePath.StopBits = PcdGet8 (PcdUartDefaultStopBits);
157a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  gSerialDevTemplate.ClockRate = PcdGet32 (PcdSerialClockRate);
158a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
159a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  return Status;
160a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni}
161a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
162a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni/**
163a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Return whether the controller is a SIO serial controller.
164a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
165a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param  Controller   The controller handle.
166a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
167a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @retval EFI_SUCCESS  The controller is a SIO serial controller.
168a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @retval others       The controller is not a SIO serial controller.
169a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni**/
170a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiEFI_STATUS
171a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiIsSioSerialController (
172a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_HANDLE               Controller
173a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  )
174a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni{
175a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_STATUS               Status;
176a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_SIO_PROTOCOL         *Sio;
177a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_DEVICE_PATH_PROTOCOL *DevicePath;
178a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  ACPI_HID_DEVICE_PATH     *Acpi;
179a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
180a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
181a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Open the IO Abstraction(s) needed to perform the supported test
182a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
183a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Status = gBS->OpenProtocol (
184a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  Controller,
185a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  &gEfiSioProtocolGuid,
186a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  (VOID **) &Sio,
187a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  gSerialControllerDriver.DriverBindingHandle,
188a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  Controller,
189a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  EFI_OPEN_PROTOCOL_BY_DRIVER
190a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  );
191a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (Status == EFI_ALREADY_STARTED) {
192a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    return EFI_SUCCESS;
193a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
194a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
195a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (!EFI_ERROR (Status)) {
196a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    //
197a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    // Close the I/O Abstraction(s) used to perform the supported test
198a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    //
199a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    gBS->CloseProtocol (
200a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           Controller,
201a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           &gEfiSioProtocolGuid,
202a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           gSerialControllerDriver.DriverBindingHandle,
203a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           Controller
204a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           );
205a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
206a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Status = gBS->OpenProtocol (
207a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      Controller,
208a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      &gEfiDevicePathProtocolGuid,
209a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      (VOID **) &DevicePath,
210a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      gSerialControllerDriver.DriverBindingHandle,
211a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      Controller,
212a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      EFI_OPEN_PROTOCOL_BY_DRIVER
213a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      );
214a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    ASSERT (Status != EFI_ALREADY_STARTED);
215a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
216a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (!EFI_ERROR (Status)) {
217a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      do {
218a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath;
219a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        DevicePath = NextDevicePathNode (DevicePath);
220a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      } while (!IsDevicePathEnd (DevicePath));
221a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
222a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      if (DevicePathType (Acpi) != ACPI_DEVICE_PATH ||
223a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          (DevicePathSubType (Acpi) != ACPI_DP && DevicePathSubType (Acpi) != ACPI_EXTENDED_DP) ||
224a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          Acpi->HID != EISA_PNP_ID (0x501)
225a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          ) {
226a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        Status = EFI_UNSUPPORTED;
227a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      }
228a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
229a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
230a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    //
231a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    // Close protocol, don't use device path protocol in the Support() function
232a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    //
233a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    gBS->CloseProtocol (
234a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      Controller,
235a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      &gEfiDevicePathProtocolGuid,
236a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      gSerialControllerDriver.DriverBindingHandle,
237a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      Controller
238a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      );
239a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
240a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  return Status;
241a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni}
242a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
243a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni/**
244a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Return whether the controller is a PCI serial controller.
245a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
246a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param  Controller   The controller handle.
247a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
248a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @retval EFI_SUCCESS  The controller is a PCI serial controller.
249a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @retval others       The controller is not a PCI serial controller.
250a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni**/
251a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiEFI_STATUS
252a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiIsPciSerialController (
253a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_HANDLE               Controller
254a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  )
255a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni{
256a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_STATUS               Status;
257a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_PCI_IO_PROTOCOL      *PciIo;
258a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_DEVICE_PATH_PROTOCOL *DevicePath;
259a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  PCI_TYPE00               Pci;
260a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  PCI_SERIAL_PARAMETER     *PciSerialParameter;
261a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
262a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
263a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Open the IO Abstraction(s) needed to perform the supported test
264a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
265a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Status = gBS->OpenProtocol (
266a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Controller,
267a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    &gEfiPciIoProtocolGuid,
268a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    (VOID **) &PciIo,
269a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    gSerialControllerDriver.DriverBindingHandle,
270a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Controller,
271a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    EFI_OPEN_PROTOCOL_BY_DRIVER
272a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    );
273a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (Status == EFI_ALREADY_STARTED) {
274a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    return EFI_SUCCESS;
275a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
276a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
277a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (!EFI_ERROR (Status)) {
278a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci);
279a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (!EFI_ERROR (Status)) {
280a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      if (!IS_PCI_16550_SERIAL (&Pci)) {
281a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        for (PciSerialParameter = (PCI_SERIAL_PARAMETER *) PcdGetPtr (PcdPciSerialParameters)
282a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni             ; PciSerialParameter->VendorId != 0xFFFF
283a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni             ; PciSerialParameter++
284a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni             ) {
285a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          if ((Pci.Hdr.VendorId == PciSerialParameter->VendorId) &&
286a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni              (Pci.Hdr.DeviceId == PciSerialParameter->DeviceId)
287a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni              ) {
288a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            break;
289a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          }
290a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        }
291a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        if (PciSerialParameter->VendorId == 0xFFFF) {
292a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          Status = EFI_UNSUPPORTED;
293a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        } else {
294a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          Status = EFI_SUCCESS;
295a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        }
296a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      }
297a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
298a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
299a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    //
300a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    // Close the I/O Abstraction(s) used to perform the supported test
301a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    //
302a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    gBS->CloseProtocol (
303a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      Controller,
304a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      &gEfiPciIoProtocolGuid,
305a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      gSerialControllerDriver.DriverBindingHandle,
306a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      Controller
307a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      );
308a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
309a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (EFI_ERROR (Status)) {
310a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    return Status;
311a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
312a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
313a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
314a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Open the EFI Device Path protocol needed to perform the supported test
315a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
316a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Status = gBS->OpenProtocol (
317a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Controller,
318a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    &gEfiDevicePathProtocolGuid,
319a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    (VOID **) &DevicePath,
320a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    gSerialControllerDriver.DriverBindingHandle,
321a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Controller,
322a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    EFI_OPEN_PROTOCOL_BY_DRIVER
323a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    );
324a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  ASSERT (Status != EFI_ALREADY_STARTED);
325a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
326a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
327a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Close protocol, don't use device path protocol in the Support() function
328a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
329a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  gBS->CloseProtocol (
330a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Controller,
331a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    &gEfiDevicePathProtocolGuid,
332a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    gSerialControllerDriver.DriverBindingHandle,
333a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Controller
334a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    );
335a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
336a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  return Status;
337a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni}
338a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
339a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni/**
340a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Check to see if this driver supports the given controller
341a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
342a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
343a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param  Controller           The handle of the controller to test.
344a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param  RemainingDevicePath  A pointer to the remaining portion of a device path.
345a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
346a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @return EFI_SUCCESS          This driver can support the given controller
347a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
348a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni**/
349a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiEFI_STATUS
350a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiEFIAPI
351a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiSerialControllerDriverSupported (
352a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
353a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN EFI_HANDLE                     Controller,
354a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
355a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  )
356a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
357a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni{
358a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_STATUS                                Status;
359a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  UART_DEVICE_PATH                          *Uart;
360a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  UART_FLOW_CONTROL_DEVICE_PATH             *FlowControl;
361a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
362a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
363a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Test RemainingDevicePath
364a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
365a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {
366a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Status = EFI_UNSUPPORTED;
367a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
368a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Uart = SkipControllerDevicePathNode (RemainingDevicePath, NULL, NULL);
369a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (DevicePathType (Uart) != MESSAGING_DEVICE_PATH ||
370a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        DevicePathSubType (Uart) != MSG_UART_DP ||
371a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        DevicePathNodeLength (Uart) != sizeof (UART_DEVICE_PATH)
372a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        ) {
373a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      return EFI_UNSUPPORTED;
374a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
375a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
376a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    //
377a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    // Do a rough check because Clock Rate is unknown until DriverBindingStart()
378a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    //
379a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (!VerifyUartParameters (0, Uart->BaudRate, Uart->DataBits, Uart->Parity, Uart->StopBits, NULL, NULL)) {
380a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      return EFI_UNSUPPORTED;
381a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
382a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
383a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);
384a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (IsUartFlowControlDevicePathNode (FlowControl)) {
385a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      //
386a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      // If the second node is Flow Control Node,
387a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      //   return error when it request other than hardware flow control.
388a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      //
389a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      if ((ReadUnaligned32 (&FlowControl->FlowControlMap) & ~UART_FLOW_CONTROL_HARDWARE) != 0) {
390a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        return EFI_UNSUPPORTED;
391a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      }
392a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
393a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
394a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
395a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Status = IsSioSerialController (Controller);
396a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (EFI_ERROR (Status)) {
397a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Status = IsPciSerialController (Controller);
398a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
399a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  return Status;
400a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni}
401a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
402a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni/**
403a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Create the child serial device instance.
404a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
405a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param Controller           The parent controller handle.
406a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param Uart                 Pointer to the UART device path node in RemainingDevicePath,
407a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                              or NULL if RemainingDevicePath is NULL.
408a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param ParentDevicePath     Pointer to the parent device path.
409a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param CreateControllerNode TRUE to create the controller node.
410a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param Instance             Instance number of the serial device.
411a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                              The value will be set to the controller node
412a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                              if CreateControllerNode is TRUE.
413a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param ParentIo             A union type pointer to either Sio or PciIo.
414a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param PciSerialParameter   The PCI serial parameter to be used by current serial device.
415a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                              NULL for SIO serial device.
416a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param PciDeviceInfo        The PCI device info for the current serial device.
417a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                              NULL for SIO serial device.
418a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
419a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @retval EFI_SUCCESS         The serial device was created successfully.
420a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @retval others              The serial device wasn't created.
421a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni**/
422a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiEFI_STATUS
423a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiCreateSerialDevice (
424a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN EFI_HANDLE                     Controller,
425a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN UART_DEVICE_PATH               *Uart,
426a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN EFI_DEVICE_PATH_PROTOCOL       *ParentDevicePath,
427a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN BOOLEAN                        CreateControllerNode,
428a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN UINT32                         Instance,
429a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN PARENT_IO_PROTOCOL_PTR         ParentIo,
430a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN PCI_SERIAL_PARAMETER           *PciSerialParameter, OPTIONAL
431a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN PCI_DEVICE_INFO                *PciDeviceInfo       OPTIONAL
432a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  )
433a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni{
434a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_STATUS                                 Status;
435a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SERIAL_DEV                                 *SerialDevice;
436a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  UINT8                                      BarIndex;
437a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  UINT64                                     Offset;
438a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  UART_FLOW_CONTROL_DEVICE_PATH              *FlowControl;
439a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  UINT32                                     FlowControlMap;
440a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  ACPI_RESOURCE_HEADER_PTR                   Resources;
441a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_ACPI_IO_PORT_DESCRIPTOR                *Io;
442a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *FixedIo;
443a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR          *AddressSpace;
444a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_DEVICE_PATH_PROTOCOL                   *TempDevicePath;
445a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
446a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  BarIndex = 0;
447a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Offset = 0;
448a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  FlowControl = NULL;
449a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  FlowControlMap = 0;
450a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
451a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
452a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Initialize the serial device instance
453a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
454a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SerialDevice = AllocateCopyPool (sizeof (SERIAL_DEV), &gSerialDevTemplate);
455a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  ASSERT (SerialDevice != NULL);
456a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
457a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SerialDevice->SerialIo.Mode    = &(SerialDevice->SerialMode);
458a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SerialDevice->ParentDevicePath = ParentDevicePath;
459a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SerialDevice->PciDeviceInfo    = PciDeviceInfo;
460a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SerialDevice->Instance         = Instance;
461a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
462a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (Uart != NULL) {
463a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    CopyMem (&SerialDevice->UartDevicePath, Uart, sizeof (UART_DEVICE_PATH));
464a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);
465a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (IsUartFlowControlDevicePathNode (FlowControl)) {
466a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      FlowControlMap = ReadUnaligned32 (&FlowControl->FlowControlMap);
467a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    } else {
468a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      FlowControl = NULL;
469a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
470a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
471a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
472a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
473a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // For PCI serial device, use the information from PCD
474a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
475a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (PciSerialParameter != NULL) {
476a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    BarIndex = (PciSerialParameter->BarIndex == PCI_BAR_ALL) ? 0 : PciSerialParameter->BarIndex;
477a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Offset = PciSerialParameter->Offset;
478a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (PciSerialParameter->RegisterStride != 0) {
479a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      SerialDevice->RegisterStride = PciSerialParameter->RegisterStride;
480a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
481a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (PciSerialParameter->ClockRate != 0) {
482a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      SerialDevice->ClockRate = PciSerialParameter->ClockRate;
483a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
484a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (PciSerialParameter->ReceiveFifoDepth != 0) {
485a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      SerialDevice->ReceiveFifoDepth = PciSerialParameter->ReceiveFifoDepth;
486a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
487a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (PciSerialParameter->TransmitFifoDepth != 0) {
488a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      SerialDevice->TransmitFifoDepth = PciSerialParameter->TransmitFifoDepth;
489a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
490a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
491a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
492a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
493a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade.
494a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // DriverBindingStart() shouldn't create a handle with different UART device path.
495a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
496a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (!VerifyUartParameters (SerialDevice->ClockRate, SerialDevice->UartDevicePath.BaudRate, SerialDevice->UartDevicePath.DataBits,
497a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                            SerialDevice->UartDevicePath.Parity, SerialDevice->UartDevicePath.StopBits, NULL, NULL
498a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                            )) {
499a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Status = EFI_INVALID_PARAMETER;
500a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    goto CreateError;
501a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
502a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
503a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (PciSerialParameter == NULL) {
504a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Status = ParentIo.Sio->GetResources (ParentIo.Sio, &Resources);
505a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  } else {
506a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Status = ParentIo.PciIo->GetBarAttributes (ParentIo.PciIo, BarIndex, NULL, (VOID **) &Resources);
507a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
508a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
509a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (!EFI_ERROR (Status)) {
510a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    //
511a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    // Get the base address information from ACPI resource descriptor.
512a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    // ACPI_IO_PORT_DESCRIPTOR and ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR are returned from Sio;
513a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    // ACPI_ADDRESS_SPACE_DESCRIPTOR is returned from PciIo.
514a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    //
515a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    while ((Resources.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) && (SerialDevice->BaseAddress == 0)) {
516a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      switch (Resources.SmallHeader->Byte) {
517a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      case ACPI_IO_PORT_DESCRIPTOR:
518a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        Io = (EFI_ACPI_IO_PORT_DESCRIPTOR *) Resources.SmallHeader;
519a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        if (Io->Length != 0) {
520a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          SerialDevice->BaseAddress = Io->BaseAddressMin;
521a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        }
522a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        break;
523a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
524a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR:
525a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        FixedIo = (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *) Resources.SmallHeader;
526a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        if (FixedIo->Length != 0) {
527a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          SerialDevice->BaseAddress = FixedIo->BaseAddress;
528a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        }
529a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        break;
530a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
531a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      case ACPI_ADDRESS_SPACE_DESCRIPTOR:
532a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        AddressSpace = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Resources.SmallHeader;
533a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        if (AddressSpace->AddrLen != 0) {
534a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          if (AddressSpace->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
535a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            SerialDevice->MmioAccess = TRUE;
536a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          }
537a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          SerialDevice->BaseAddress = AddressSpace->AddrRangeMin + Offset;
538a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        }
539a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        break;
540a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      }
541a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
542a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      if (Resources.SmallHeader->Bits.Type == 0) {
543a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        Resources.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) Resources.SmallHeader
544a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                                                                + Resources.SmallHeader->Bits.Length
545a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                                                                + sizeof (*Resources.SmallHeader));
546a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      } else {
547a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        Resources.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) Resources.LargeHeader
548a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                                                                + Resources.LargeHeader->Length
549a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                                                                + sizeof (*Resources.LargeHeader));
550a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      }
551a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
552a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
553a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
554a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (SerialDevice->BaseAddress == 0) {
555a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Status = EFI_INVALID_PARAMETER;
556a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    goto CreateError;
557a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
558a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
559a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SerialDevice->HardwareFlowControl = (BOOLEAN) (FlowControlMap == UART_FLOW_CONTROL_HARDWARE);
560a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
561a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
562a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Report status code the serial present
563a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
564a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
565a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    EFI_PROGRESS_CODE,
566a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    EFI_P_PC_PRESENCE_DETECT | EFI_PERIPHERAL_SERIAL_PORT,
567a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    SerialDevice->ParentDevicePath
568a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    );
569a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
570a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (!SerialPresent (SerialDevice)) {
571a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Status = EFI_DEVICE_ERROR;
572a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
573a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      EFI_ERROR_CODE,
574a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      EFI_P_EC_NOT_DETECTED | EFI_PERIPHERAL_SERIAL_PORT,
575a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      SerialDevice->ParentDevicePath
576a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      );
577a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    goto CreateError;
578a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
579a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
580a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
581a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // 1. Append Controller device path node.
582a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
583a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (CreateControllerNode) {
584a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    mControllerDevicePathTemplate.ControllerNumber = SerialDevice->Instance;
585a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    SerialDevice->DevicePath = AppendDevicePathNode (
586a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                                 SerialDevice->ParentDevicePath,
587a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                                 (EFI_DEVICE_PATH_PROTOCOL *) &mControllerDevicePathTemplate
588a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                                 );
589a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    SerialDevice->ContainsControllerNode = TRUE;
590a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
591a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
592a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
593a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // 2. Append UART device path node.
594a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //    The Uart setings are zero here.
595a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //    SetAttribute() will update them to match the default setings.
596a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
597a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  TempDevicePath = SerialDevice->DevicePath;
598a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (TempDevicePath != NULL) {
599a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    SerialDevice->DevicePath = AppendDevicePathNode (
600a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                                 TempDevicePath,
601a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                                 (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath
602a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                                 );
603a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    FreePool (TempDevicePath);
604a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  } else {
605a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    SerialDevice->DevicePath = AppendDevicePathNode (
606a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                                 SerialDevice->ParentDevicePath,
607a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                                 (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath
608a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                                 );
609a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
610a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
611a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // 3. Append the Flow Control device path node.
612a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //    Only produce the Flow Control node when remaining device path has it
613a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
614a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (FlowControl != NULL) {
615a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    TempDevicePath = SerialDevice->DevicePath;
616a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (TempDevicePath != NULL) {
617a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      SerialDevice->DevicePath = AppendDevicePathNode (
618a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                                   TempDevicePath,
619a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                                   (EFI_DEVICE_PATH_PROTOCOL *) FlowControl
620a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                                   );
621a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      FreePool (TempDevicePath);
622a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
623a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
624a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  ASSERT (SerialDevice->DevicePath != NULL);
625a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
626a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
627a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.
628a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
629a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SerialDevice->SerialMode.BaudRate = SerialDevice->UartDevicePath.BaudRate;
630a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SerialDevice->SerialMode.DataBits = SerialDevice->UartDevicePath.DataBits;
631a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SerialDevice->SerialMode.Parity   = SerialDevice->UartDevicePath.Parity;
632a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SerialDevice->SerialMode.StopBits = SerialDevice->UartDevicePath.StopBits;
633a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
634a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
635a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Issue a reset to initialize the COM port
636a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
637a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Status = SerialDevice->SerialIo.Reset (&SerialDevice->SerialIo);
638a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (EFI_ERROR (Status)) {
639a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
640a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      EFI_ERROR_CODE,
641a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      EFI_P_EC_CONTROLLER_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
642a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      SerialDevice->DevicePath
643a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      );
644a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    goto CreateError;
645a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
646a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
647a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  AddName (SerialDevice, Instance);
648a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
649a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Install protocol interfaces for the serial device.
650a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
651a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Status = gBS->InstallMultipleProtocolInterfaces (
652a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  &SerialDevice->Handle,
653a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,
654a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,
655a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  NULL
656a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  );
657a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (EFI_ERROR (Status)) {
658a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    goto CreateError;
659a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
660a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
661a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Open For Child Device
662a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
663a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Status = gBS->OpenProtocol (
664a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  Controller,
665a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  PciSerialParameter != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
666a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  (VOID **) &ParentIo,
667a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  gSerialControllerDriver.DriverBindingHandle,
668a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  SerialDevice->Handle,
669a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
670a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  );
671a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
672a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (EFI_ERROR (Status)) {
673a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    gBS->UninstallMultipleProtocolInterfaces (
674a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           &SerialDevice->Handle,
675a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,
676a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,
677a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           NULL
678a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           );
679a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
680a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
681a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiCreateError:
682a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (EFI_ERROR (Status)) {
683a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (SerialDevice->DevicePath != NULL) {
684a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      FreePool (SerialDevice->DevicePath);
685a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
686a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (SerialDevice->ControllerNameTable != NULL) {
687a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      FreeUnicodeStringTable (SerialDevice->ControllerNameTable);
688a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
689a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    FreePool (SerialDevice);
690a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
691a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  return Status;
692a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni}
693a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
694a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni/**
695a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Returns an array of pointers containing all the child serial device pointers.
696a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
697a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param Controller      The parent controller handle.
698a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param IoProtocolGuid  The protocol GUID, either equals to gEfiSioProtocolGuid
699a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                         or equals to gEfiPciIoProtocolGuid.
700a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param Count           Count of the serial devices.
701a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
702a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @return  An array of pointers containing all the child serial device pointers.
703a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni**/
704a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiSERIAL_DEV **
705a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiGetChildSerialDevices (
706a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN EFI_HANDLE                       Controller,
707a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN EFI_GUID                         *IoProtocolGuid,
708a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  OUT UINTN                           *Count
709a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  )
710a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni{
711a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_STATUS                                 Status;
712a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  UINTN                                      Index;
713a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_OPEN_PROTOCOL_INFORMATION_ENTRY        *OpenInfoBuffer;
714a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  UINTN                                      EntryCount;
715a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SERIAL_DEV                                 **SerialDevices;
716a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_SERIAL_IO_PROTOCOL                     *SerialIo;
717a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  BOOLEAN                                    OpenByDriver;
718a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
719a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  *Count = 0;
720a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
721a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // If the SerialIo instance specified by RemainingDevicePath is already created,
722a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // update the attributes/control.
723a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
724a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Status = gBS->OpenProtocolInformation (
725a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Controller,
726a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    IoProtocolGuid,
727a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    &OpenInfoBuffer,
728a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    &EntryCount
729a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    );
730a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (EFI_ERROR (Status)) {
731a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    return NULL;
732a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
733a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
734a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SerialDevices = AllocatePool (EntryCount * sizeof (SERIAL_DEV *));
735a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  ASSERT (SerialDevices != NULL);
736a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
737a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  *Count = 0;
738a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  OpenByDriver = FALSE;
739a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  for (Index = 0; Index < EntryCount; Index++) {
740a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
741a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      Status = gBS->OpenProtocol (
742a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        OpenInfoBuffer[Index].ControllerHandle,
743a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        &gEfiSerialIoProtocolGuid,
744a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        (VOID **) &SerialIo,
745a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        gSerialControllerDriver.DriverBindingHandle,
746a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        Controller,
747a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        EFI_OPEN_PROTOCOL_GET_PROTOCOL
748a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        );
749a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      if (!EFI_ERROR (Status)) {
750a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        SerialDevices[(*Count)++] = SERIAL_DEV_FROM_THIS (SerialIo);
751a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      }
752a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
753a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
754a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
755a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
756a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      ASSERT (OpenInfoBuffer[Index].AgentHandle == gSerialControllerDriver.DriverBindingHandle);
757a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      OpenByDriver = TRUE;
758a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
759a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
760a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (OpenInfoBuffer != NULL) {
761a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    FreePool (OpenInfoBuffer);
762a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
763a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
764a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  ASSERT ((*Count == 0) || (OpenByDriver));
765a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
766a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  return SerialDevices;
767a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni}
768a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
769a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni/**
770a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Start to management the controller passed in
771a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
772a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
773a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param  Controller           The handle of the controller to test.
774a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param  RemainingDevicePath  A pointer to the remaining portion of a device path.
775a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
776a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @return EFI_SUCCESS   Driver is started successfully
777a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni**/
778a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiEFI_STATUS
779a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiEFIAPI
780a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiSerialControllerDriverStart (
781a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
782a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN EFI_HANDLE                     Controller,
783a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
784a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  )
785a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni{
786a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_STATUS                                 Status;
787a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  UINTN                                      Index;
788a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_DEVICE_PATH_PROTOCOL                   *ParentDevicePath;
789a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_DEVICE_PATH_PROTOCOL                   *Node;
790a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_SERIAL_IO_PROTOCOL                     *SerialIo;
791a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  UINT32                                     ControllerNumber;
792a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  UART_DEVICE_PATH                           *Uart;
793a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  UART_FLOW_CONTROL_DEVICE_PATH              *FlowControl;
794a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  UINT32                                     Control;
795a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  PARENT_IO_PROTOCOL_PTR                     ParentIo;
796a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  ACPI_HID_DEVICE_PATH                       *Acpi;
797a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_GUID                                   *IoProtocolGuid;
798a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  PCI_SERIAL_PARAMETER                       *PciSerialParameter;
799a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  PCI_SERIAL_PARAMETER                       DefaultPciSerialParameter;
800a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  PCI_TYPE00                                 Pci;
801a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  UINT32                                     PciSerialCount;
802a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SERIAL_DEV                                 **SerialDevices;
803a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  UINTN                                      SerialDeviceCount;
804a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  PCI_DEVICE_INFO                            *PciDeviceInfo;
805a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  UINT64                                     Supports;
806a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  BOOLEAN                                    ContainsControllerNode;
807a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
808a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
809a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Get the Parent Device Path
810a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
811a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Status = gBS->OpenProtocol (
812a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  Controller,
813a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  &gEfiDevicePathProtocolGuid,
814a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  (VOID **) &ParentDevicePath,
815a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  This->DriverBindingHandle,
816a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  Controller,
817a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  EFI_OPEN_PROTOCOL_BY_DRIVER
818a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  );
819a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
820a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    return Status;
821a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
822a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
823a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Report status code enable the serial
824a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
825a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
826a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    EFI_PROGRESS_CODE,
827a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    EFI_P_PC_ENABLE | EFI_PERIPHERAL_SERIAL_PORT,
828a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    ParentDevicePath
829a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    );
830a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
831a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
832a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Grab the IO abstraction we need to get any work done
833a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
834a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IoProtocolGuid = &gEfiSioProtocolGuid;
835a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Status = gBS->OpenProtocol (
836a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  Controller,
837a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  IoProtocolGuid,
838a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  (VOID **) &ParentIo,
839a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  This->DriverBindingHandle,
840a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  Controller,
841a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  EFI_OPEN_PROTOCOL_BY_DRIVER
842a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  );
843a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
844a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    IoProtocolGuid = &gEfiPciIoProtocolGuid;
845a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Status = gBS->OpenProtocol (
846a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    Controller,
847a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    IoProtocolGuid,
848a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    (VOID **) &ParentIo,
849a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    This->DriverBindingHandle,
850a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    Controller,
851a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    EFI_OPEN_PROTOCOL_BY_DRIVER
852a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    );
853a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
854a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  ASSERT (!EFI_ERROR (Status) || Status == EFI_ALREADY_STARTED);
855a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
856a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
857a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Do nothing for END device path node
858a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
859a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {
860a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    return EFI_SUCCESS;
861a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
862a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
86383809dc0186eea34a9b0db6df306abe9e1c7776bMichael Kinney  ControllerNumber = 0;
86483809dc0186eea34a9b0db6df306abe9e1c7776bMichael Kinney  ContainsControllerNode = FALSE;
865a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SerialDevices = GetChildSerialDevices (Controller, IoProtocolGuid, &SerialDeviceCount);
866a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
867a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // If the SerialIo instance specified by RemainingDevicePath is already created,
868a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // update the attributes/control.
869a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
870a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if ((SerialDeviceCount != 0) && (RemainingDevicePath != NULL)) {
871a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);
872a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    for (Index = 0; Index < SerialDeviceCount; Index++) {
87312f5ff97f6c1f87370213a00d0b36e8208beacf9Feng Tian      ASSERT ((SerialDevices != NULL) && (SerialDevices[Index] != NULL));
874a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      if ((!SerialDevices[Index]->ContainsControllerNode && !ContainsControllerNode) ||
875a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          (SerialDevices[Index]->ContainsControllerNode && ContainsControllerNode && SerialDevices[Index]->Instance == ControllerNumber)
876a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          ) {
87783809dc0186eea34a9b0db6df306abe9e1c7776bMichael Kinney        SerialIo = &SerialDevices[Index]->SerialIo;
878a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        Status = EFI_INVALID_PARAMETER;
879a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        //
880a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade.
881a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        // DriverBindingStart() shouldn't create a handle with different UART device path.
882a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        //
883a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        if (VerifyUartParameters (SerialDevices[Index]->ClockRate, Uart->BaudRate, Uart->DataBits,
884a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                                  (EFI_PARITY_TYPE) Uart->Parity, (EFI_STOP_BITS_TYPE) Uart->StopBits, NULL, NULL)) {
885a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          Status = SerialIo->SetAttributes (
886a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                               SerialIo,
887a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                               Uart->BaudRate,
888a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                               SerialIo->Mode->ReceiveFifoDepth,
889a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                               SerialIo->Mode->Timeout,
890a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                               (EFI_PARITY_TYPE) Uart->Parity,
891a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                               Uart->DataBits,
892a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                               (EFI_STOP_BITS_TYPE) Uart->StopBits
893a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                               );
894a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        }
895a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);
896a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        if (!EFI_ERROR (Status) && IsUartFlowControlDevicePathNode (FlowControl)) {
897a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          Status = SerialIo->GetControl (SerialIo, &Control);
898a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          if (!EFI_ERROR (Status)) {
899a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            if (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) {
900a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni              Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
901a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            } else {
902a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni              Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
903a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            }
904a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            //
905a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            // Clear the bits that are not allowed to pass to SetControl
906a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            //
907a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            Control &= (EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
908a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                        EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
909a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                        EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE);
910a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            Status = SerialIo->SetControl (SerialIo, Control);
911a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          }
912a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        }
913a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        break;
914a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      }
915a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
916a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (Index != SerialDeviceCount) {
917a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      //
918a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      // Directly return if the SerialIo instance specified by RemainingDevicePath is found and updated.
919a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      // Otherwise continue to create the instance specified by RemainingDevicePath.
920a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      //
921a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      if (SerialDevices != NULL) {
922a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        FreePool (SerialDevices);
923a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      }
924a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      return Status;
925a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
926a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
927a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
928a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (RemainingDevicePath != NULL) {
929a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);
930a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  } else {
931a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Uart = NULL;
932a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
933a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
934a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  PciDeviceInfo = NULL;
935a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (IoProtocolGuid == &gEfiSioProtocolGuid) {
936a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Status = EFI_NOT_FOUND;
937a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (RemainingDevicePath == NULL || !ContainsControllerNode) {
938a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      Node = ParentDevicePath;
939a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      do {
940a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        Acpi = (ACPI_HID_DEVICE_PATH *) Node;
941a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        Node = NextDevicePathNode (Node);
942a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      } while (!IsDevicePathEnd (Node));
943a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, Acpi->UID, ParentIo, NULL, NULL);
944a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      DEBUG ((EFI_D_INFO, "PciSioSerial: Create SIO child serial device - %r\n", Status));
945a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
946a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  } else {
947a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Status = ParentIo.PciIo->Pci.Read (ParentIo.PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci);
948a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (!EFI_ERROR (Status)) {
949a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      //
950a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      // PcdPciSerialParameters takes the higher priority.
951a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      //
952a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      PciSerialCount = 0;
953a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) {
954a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) &&
955a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId)
956a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            ) {
957a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          PciSerialCount++;
958a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        }
959a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      }
960a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
961a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      if (SerialDeviceCount == 0) {
962a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        //
963a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        // Enable the IO & MEM decoding when creating the first child.
964a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        // Restore the PCI attributes when all children is destroyed (PciDeviceInfo->ChildCount == 0).
965a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        //
966a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        PciDeviceInfo = AllocatePool (sizeof (PCI_DEVICE_INFO));
96712f5ff97f6c1f87370213a00d0b36e8208beacf9Feng Tian        ASSERT (PciDeviceInfo != NULL);
968a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        PciDeviceInfo->ChildCount = 0;
969a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        PciDeviceInfo->PciIo = ParentIo.PciIo;
970a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        Status = ParentIo.PciIo->Attributes (
971a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          ParentIo.PciIo,
972a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          EfiPciIoAttributeOperationGet,
973a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          0,
974a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          &PciDeviceInfo->PciAttributes
975a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          );
976a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
977a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        if (!EFI_ERROR (Status)) {
978a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          Status = ParentIo.PciIo->Attributes (
979a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            ParentIo.PciIo,
980a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            EfiPciIoAttributeOperationSupported,
981a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            0,
982a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            &Supports
983a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            );
984a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          if (!EFI_ERROR (Status)) {
985d14198b3397d85da37d8a9f81cf233ce08c7758aFeng Tian            Supports &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY);
986a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            Status = ParentIo.PciIo->Attributes (
987a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni              ParentIo.PciIo,
988a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni              EfiPciIoAttributeOperationEnable,
989a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni              Supports,
990a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni              NULL
991a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni              );
992a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          }
993a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        }
994a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      } else {
995a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        //
996a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        // Re-use the PciDeviceInfo stored in existing children.
997a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        //
99812f5ff97f6c1f87370213a00d0b36e8208beacf9Feng Tian        ASSERT ((SerialDevices != NULL) && (SerialDevices[0] != NULL));
999a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        PciDeviceInfo = SerialDevices[0]->PciDeviceInfo;
1000a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        ASSERT (PciDeviceInfo != NULL);
1001a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      }
1002a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1003a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      Status = EFI_NOT_FOUND;
1004a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      if (PciSerialCount <= 1) {
1005a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        //
1006a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        // PCI serial device contains only one UART
1007a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        //
1008a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        if (RemainingDevicePath == NULL || !ContainsControllerNode) {
1009a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          //
1010a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          // This PCI serial device is matched by class code in Supported()
1011a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          //
1012a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          if (PciSerialCount == 0) {
1013a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            DefaultPciSerialParameter.VendorId = Pci.Hdr.VendorId;
1014a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            DefaultPciSerialParameter.DeviceId = Pci.Hdr.DeviceId;
1015a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            DefaultPciSerialParameter.BarIndex = 0;
1016a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            DefaultPciSerialParameter.Offset = 0;
1017a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            DefaultPciSerialParameter.RegisterStride = 0;
1018a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            DefaultPciSerialParameter.ClockRate = 0;
1019a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            PciSerialParameter = &DefaultPciSerialParameter;
1020a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          } else if (PciSerialCount == 1) {
1021a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            PciSerialParameter = PcdGetPtr (PcdPciSerialParameters);
1022a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          }
1023a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1024a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, 0, ParentIo, PciSerialParameter, PciDeviceInfo);
1025a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device (single) - %r\n", Status));
1026a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          if (!EFI_ERROR (Status)) {
1027a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            PciDeviceInfo->ChildCount++;
1028a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          }
1029a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        }
1030a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      } else {
1031a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        //
1032a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        // PCI serial device contains multiple UARTs
1033a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        //
1034a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        if (RemainingDevicePath == NULL || ContainsControllerNode) {
1035a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          PciSerialCount = 0;
1036a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) {
1037a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) &&
1038a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId) &&
1039a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                ((RemainingDevicePath == NULL) || (ControllerNumber == PciSerialCount))
1040a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                ) {
1041a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni              //
1042a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni              // Create controller node when PCI serial device contains multiple UARTs
1043a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni              //
1044a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni              Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, TRUE, PciSerialCount, ParentIo, PciSerialParameter, PciDeviceInfo);
1045a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni              PciSerialCount++;
1046a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni              DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device (multiple) - %r\n", Status));
1047a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni              if (!EFI_ERROR (Status)) {
1048a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                PciDeviceInfo->ChildCount++;
1049a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni              }
1050a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni            }
1051a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          }
1052a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        }
1053a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      }
1054a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
1055a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
1056a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1057a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (SerialDevices != NULL) {
1058a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    FreePool (SerialDevices);
1059a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
1060a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1061a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
1062a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // For multiple PCI serial devices, set Status to SUCCESS if one child is created successfully
1063a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
1064a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount != 0)) {
1065a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Status = EFI_SUCCESS;
1066a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
1067a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1068a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (EFI_ERROR (Status) && (SerialDeviceCount == 0)) {
1069a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (PciDeviceInfo != NULL) {
1070a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      Status = ParentIo.PciIo->Attributes (
1071a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        ParentIo.PciIo,
1072a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        EfiPciIoAttributeOperationSet,
1073a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        PciDeviceInfo->PciAttributes,
1074a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        NULL
1075a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        );
1076a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      ASSERT_EFI_ERROR (Status);
1077a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      FreePool (PciDeviceInfo);
1078a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
1079a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    gBS->CloseProtocol (
1080a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           Controller,
1081a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           &gEfiDevicePathProtocolGuid,
1082a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           This->DriverBindingHandle,
1083a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           Controller
1084a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           );
1085a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    gBS->CloseProtocol (
1086a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           Controller,
1087a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           IoProtocolGuid,
1088a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           This->DriverBindingHandle,
1089a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           Controller
1090a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           );
1091a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
1092a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1093a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  return Status;
1094a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni}
1095a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1096a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni/**
1097a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Disconnect this driver with the controller, uninstall related protocol instance
1098a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1099a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param  This                  A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1100a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param  Controller            The handle of the controller to test.
1101a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param  NumberOfChildren      Number of child device.
1102a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @param  ChildHandleBuffer     A pointer to the remaining portion of a device path.
1103a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1104a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @retval EFI_SUCCESS           Operation successfully
1105a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  @retval EFI_DEVICE_ERROR      Cannot stop the driver successfully
1106a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1107a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni**/
1108a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiEFI_STATUS
1109a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiEFIAPI
1110a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu NiSerialControllerDriverStop (
1111a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
1112a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN  EFI_HANDLE                     Controller,
1113a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN  UINTN                          NumberOfChildren,
1114a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  IN  EFI_HANDLE                     *ChildHandleBuffer
1115a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  )
1116a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1117a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni{
1118a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_STATUS                          Status;
1119a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  UINTN                               Index;
1120a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  BOOLEAN                             AllChildrenStopped;
1121a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_SERIAL_IO_PROTOCOL              *SerialIo;
1122a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  SERIAL_DEV                          *SerialDevice;
1123a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  VOID                                *IoProtocol;
1124a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  EFI_DEVICE_PATH_PROTOCOL            *DevicePath;
1125a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  PCI_DEVICE_INFO                     *PciDeviceInfo;
1126a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1127a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  PciDeviceInfo = NULL;
1128a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1129a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  Status = gBS->HandleProtocol (
1130a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  Controller,
1131a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  &gEfiDevicePathProtocolGuid,
1132a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  (VOID **) &DevicePath
1133a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                  );
1134a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1135a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
1136a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  // Report the status code disable the serial
1137a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  //
1138a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1139a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    EFI_PROGRESS_CODE,
1140a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    EFI_P_PC_DISABLE | EFI_PERIPHERAL_SERIAL_PORT,
1141a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    DevicePath
1142a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    );
1143a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1144a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (NumberOfChildren == 0) {
1145a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    //
1146a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    // Close the bus driver
1147a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    //
1148a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Status = gBS->OpenProtocol (
1149a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    Controller,
1150a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    &gEfiPciIoProtocolGuid,
1151a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    &IoProtocol,
1152a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    This->DriverBindingHandle,
1153a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    Controller,
1154a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    EFI_OPEN_PROTOCOL_TEST_PROTOCOL
1155a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    );
1156a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    gBS->CloseProtocol (
1157a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           Controller,
1158a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           !EFI_ERROR (Status) ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
1159a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           This->DriverBindingHandle,
1160a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           Controller
1161a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           );
1162a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1163a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    gBS->CloseProtocol (
1164a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           Controller,
1165a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           &gEfiDevicePathProtocolGuid,
1166a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           This->DriverBindingHandle,
1167a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           Controller
1168a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni           );
1169a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    return EFI_SUCCESS;
1170a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
1171a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1172a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  AllChildrenStopped = TRUE;
1173a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1174a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  for (Index = 0; Index < NumberOfChildren; Index++) {
1175a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1176a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    Status = gBS->OpenProtocol (
1177a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    ChildHandleBuffer[Index],
1178a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    &gEfiSerialIoProtocolGuid,
1179a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    (VOID **) &SerialIo,
1180a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    This->DriverBindingHandle,
1181a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    Controller,
1182a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
1183a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                    );
1184a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (!EFI_ERROR (Status)) {
1185a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1186a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo);
1187a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      ASSERT ((PciDeviceInfo == NULL) || (PciDeviceInfo == SerialDevice->PciDeviceInfo));
1188a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      PciDeviceInfo = SerialDevice->PciDeviceInfo;
1189a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1190a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      Status = gBS->CloseProtocol (
1191a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                      Controller,
1192a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                      PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
1193a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                      This->DriverBindingHandle,
1194a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                      ChildHandleBuffer[Index]
1195a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                      );
1196a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1197a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      Status = gBS->UninstallMultipleProtocolInterfaces (
1198a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                      ChildHandleBuffer[Index],
1199a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                      &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,
1200a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                      &gEfiSerialIoProtocolGuid,   &SerialDevice->SerialIo,
1201a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                      NULL
1202a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni                      );
1203a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      if (EFI_ERROR (Status)) {
1204a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        gBS->OpenProtocol (
1205a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni               Controller,
1206a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni               PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
1207a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni               &IoProtocol,
1208a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni               This->DriverBindingHandle,
1209a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni               ChildHandleBuffer[Index],
1210a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni               EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1211a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni               );
1212a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      } else {
1213a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        FreePool (SerialDevice->DevicePath);
1214a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        FreeUnicodeStringTable (SerialDevice->ControllerNameTable);
1215a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        FreePool (SerialDevice);
1216a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1217a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        if (PciDeviceInfo != NULL) {
1218a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          ASSERT (PciDeviceInfo->ChildCount != 0);
1219a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni          PciDeviceInfo->ChildCount--;
1220a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        }
1221a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      }
1222a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
1223a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1224a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if (EFI_ERROR (Status)) {
1225a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      AllChildrenStopped = FALSE;
1226a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
1227a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
1228a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni
1229a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  if (!AllChildrenStopped) {
1230a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    return EFI_DEVICE_ERROR;
1231a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  } else {
1232a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    //
1233a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    // If all children are destroyed, restore the PCI attributes.
1234a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    //
1235a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount == 0)) {
1236a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      ASSERT (PciDeviceInfo->PciIo != NULL);
1237a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      Status = PciDeviceInfo->PciIo->Attributes (
1238a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        PciDeviceInfo->PciIo,
1239a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        EfiPciIoAttributeOperationSet,
1240a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        PciDeviceInfo->PciAttributes,
1241a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        NULL
1242a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni        );
1243a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      ASSERT_EFI_ERROR (Status);
1244a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni      FreePool (PciDeviceInfo);
1245a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    }
1246a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni    return EFI_SUCCESS;
1247a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni  }
1248a59e2edebeb2762af458aa63725f5bb0facb7c5eRuiyu Ni}
1249