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