]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c
Adjust directory structures.
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciDeviceSupport.c
diff --git a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c
new file mode 100644 (file)
index 0000000..0e95dc1
--- /dev/null
@@ -0,0 +1,1351 @@
+/*++\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  PciDeviceSupport.c\r
+\r
+Abstract:\r
+\r
+  This file provides routine to support Pci device node manipulation\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "pcibus.h"\r
+#include "PciDeviceSupport.h"\r
+\r
+//\r
+// This device structure is serviced as a header.\r
+// Its Next field points to the first root bridge device node\r
+//\r
+LIST_ENTRY  gPciDevicePool;\r
+\r
+EFI_STATUS\r
+InitializePciDevicePool (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Initialize the gPciDevicePool\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+{\r
+  InitializeListHead (&gPciDevicePool);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+InsertRootBridge (\r
+  PCI_IO_DEVICE *RootBridge\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Insert a root bridge into PCI device pool\r
+\r
+Arguments:\r
+\r
+  RootBridge    - A pointer to the PCI_IO_DEVICE.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+{\r
+\r
+  InsertTailList (&gPciDevicePool, &(RootBridge->Link));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+InsertPciDevice (\r
+  PCI_IO_DEVICE *Bridge,\r
+  PCI_IO_DEVICE *PciDeviceNode\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This function is used to insert a PCI device node under\r
+  a bridge\r
+\r
+Arguments:\r
+  Bridge        - A pointer to the PCI_IO_DEVICE.\r
+  PciDeviceNode - A pointer to the PCI_IO_DEVICE.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+{\r
+\r
+  InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link));\r
+  PciDeviceNode->Parent = Bridge;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+DestroyRootBridge (\r
+  IN PCI_IO_DEVICE *RootBridge\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+\r
+Arguments:\r
+\r
+  RootBridge   - A pointer to the PCI_IO_DEVICE.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+{\r
+  DestroyPciDeviceTree (RootBridge);\r
+\r
+  FreePciDevice (RootBridge);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+FreePciDevice (\r
+  IN PCI_IO_DEVICE *PciIoDevice\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Destroy a pci device node.\r
+  Also all direct or indirect allocated resource for this node will be freed.\r
+\r
+Arguments:\r
+\r
+  PciIoDevice   - A pointer to the PCI_IO_DEVICE.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+{\r
+\r
+  //\r
+  // Assume all children have been removed underneath this device\r
+  //\r
+  if (PciIoDevice->ResourcePaddingDescriptors != NULL) {\r
+    gBS->FreePool (PciIoDevice->ResourcePaddingDescriptors);\r
+  }\r
+\r
+  if (PciIoDevice->DevicePath != NULL) {\r
+    gBS->FreePool (PciIoDevice->DevicePath);\r
+  }\r
+\r
+  gBS->FreePool (PciIoDevice);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+DestroyPciDeviceTree (\r
+  IN PCI_IO_DEVICE *Bridge\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Destroy all the pci device node under the bridge.\r
+  Bridge itself is not included.\r
+\r
+Arguments:\r
+\r
+  Bridge   - A pointer to the PCI_IO_DEVICE.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+{\r
+  LIST_ENTRY      *CurrentLink;\r
+  PCI_IO_DEVICE   *Temp;\r
+\r
+  while (!IsListEmpty (&Bridge->ChildList)) {\r
+\r
+    CurrentLink = Bridge->ChildList.ForwardLink;\r
+\r
+    //\r
+    // Remove this node from the linked list\r
+    //\r
+    RemoveEntryList (CurrentLink);\r
+\r
+    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+\r
+    if (!IsListEmpty (&Temp->ChildList)) {\r
+      DestroyPciDeviceTree (Temp);\r
+    }\r
+\r
+    FreePciDevice (Temp);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+DestroyRootBridgeByHandle (\r
+  EFI_HANDLE Controller\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Destroy all device nodes under the root bridge\r
+  specified by Controller.\r
+  The root bridge itself is also included.\r
+\r
+Arguments:\r
+\r
+  Controller   - An efi handle.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+// TODO:    EFI_NOT_FOUND - add return value to function comment\r
+{\r
+\r
+  LIST_ENTRY      *CurrentLink;\r
+  PCI_IO_DEVICE   *Temp;\r
+\r
+  CurrentLink = gPciDevicePool.ForwardLink;\r
+\r
+  while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
+    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+\r
+    if (Temp->Handle == Controller) {\r
+\r
+      RemoveEntryList (CurrentLink);\r
+\r
+      DestroyPciDeviceTree (Temp);\r
+\r
+      FreePciDevice (Temp);\r
+\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    CurrentLink = CurrentLink->ForwardLink;\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+EFI_STATUS\r
+RegisterPciDevice (\r
+  IN  EFI_HANDLE                     Controller,\r
+  IN  PCI_IO_DEVICE                  *PciIoDevice,\r
+  OUT EFI_HANDLE                     *Handle OPTIONAL\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This function registers the PCI IO device. It creates a handle for this PCI IO device\r
+  (if the handle does not exist), attaches appropriate protocols onto the handle, does\r
+  necessary initialization, and sets up parent/child relationship with its bus controller.\r
+\r
+Arguments:\r
+\r
+  Controller    - An EFI handle for the PCI bus controller.\r
+  PciIoDevice   - A PCI_IO_DEVICE pointer to the PCI IO device to be registered.\r
+  Handle        - A pointer to hold the EFI handle for the PCI IO device.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS   - The PCI device is successfully registered.\r
+  Others        - An error occurred when registering the PCI device.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS          Status;\r
+  VOID                *PlatformOpRomBuffer;\r
+  UINTN               PlatformOpRomSize;\r
+  UINT8               PciExpressCapRegOffset;\r
+  EFI_PCI_IO_PROTOCOL *PciIo;\r
+  UINT8               Data8;\r
+\r
+  //\r
+  // Install the pciio protocol, device path protocol\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &PciIoDevice->Handle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  PciIoDevice->DevicePath,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  &PciIoDevice->PciIo,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Detect if PCI Express Device\r
+  //\r
+  PciExpressCapRegOffset = 0;\r
+  Status = LocateCapabilityRegBlock (\r
+             PciIoDevice,\r
+             EFI_PCI_CAPABILITY_ID_PCIEXP,\r
+             &PciExpressCapRegOffset,\r
+             NULL\r
+             );\r
+  if (!EFI_ERROR (Status)) {\r
+    PciIoDevice->IsPciExp = TRUE;\r
+  }\r
+  \r
+  //\r
+  // Force Interrupt line to "Unknown" or "No Connection"\r
+  //\r
+  PciIo = &(PciIoDevice->PciIo);\r
+  Data8 = PCI_INT_LINE_UNKNOWN;\r
+  PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);\r
+\r
+  //\r
+  // Process Platform OpRom\r
+  //\r
+  if (gPciPlatformProtocol != NULL && !PciIoDevice->AllOpRomProcessed) {\r
+    PciIoDevice->AllOpRomProcessed = TRUE;\r
+\r
+    Status = gPciPlatformProtocol->GetPciRom (\r
+                                     gPciPlatformProtocol,\r
+                                     PciIoDevice->Handle,\r
+                                     &PlatformOpRomBuffer,\r
+                                     &PlatformOpRomSize\r
+                                     );\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+\r
+      //\r
+      // Have Platform OpRom\r
+      //\r
+      PciIoDevice->RomSize        = PlatformOpRomSize;\r
+      PciIoDevice->PciIo.RomSize  = PlatformOpRomSize;\r
+      PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;\r
+\r
+      //\r
+      // Process Image\r
+      //\r
+      ProcessOpRomImage (PciIoDevice);\r
+    }\r
+  }\r
+\r
+  if (PciIoDevice->BusOverride) {\r
+    //\r
+    // Install BusSpecificDriverOverride Protocol\r
+    //\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &PciIoDevice->Handle,\r
+                    &gEfiBusSpecificDriverOverrideProtocolGuid,\r
+                    &PciIoDevice->PciDriverOverride,\r
+                    NULL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      gBS->UninstallMultipleProtocolInterfaces (\r
+             &PciIoDevice->Handle,\r
+             &gEfiDevicePathProtocolGuid,\r
+             PciIoDevice->DevicePath,\r
+             &gEfiPciIoProtocolGuid,\r
+             &PciIoDevice->PciIo,\r
+             NULL\r
+             );\r
+\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciRootBridgeIoProtocolGuid,\r
+                  (VOID **) &(PciIoDevice->PciRootBridgeIo),\r
+                  gPciBusDriverBinding.DriverBindingHandle,\r
+                  PciIoDevice->Handle,\r
+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Install Pccard Hotplug GUID for Pccard device so that\r
+  // to notify CardBus driver to stop the device when de-register happens\r
+  //\r
+  InstallPciHotplugGuid (PciIoDevice);\r
+\r
+  if (Handle != NULL) {\r
+    *Handle = PciIoDevice->Handle;\r
+  }\r
+\r
+  //\r
+  // Indicate the pci device is registered\r
+  //\r
+  PciIoDevice->Registered = TRUE;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+RemoveAllPciDeviceOnBridge (\r
+  EFI_HANDLE               RootBridgeHandle,\r
+  PCI_IO_DEVICE            *Bridge\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This function is used to remove the whole PCI devices from the bridge.\r
+\r
+Arguments:\r
+\r
+  RootBridgeHandle   - An efi handle.\r
+  Bridge             - A pointer to the PCI_IO_DEVICE.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+{\r
+\r
+  LIST_ENTRY      *CurrentLink;\r
+  PCI_IO_DEVICE   *Temp;\r
+\r
+  while (!IsListEmpty (&Bridge->ChildList)) {\r
+\r
+    CurrentLink = Bridge->ChildList.ForwardLink;\r
+    Temp        = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+\r
+    //\r
+    // Check if the current node has been deregistered before\r
+    // If it is not, then deregister it\r
+    //\r
+    if (Temp->Registered) {\r
+      DeRegisterPciDevice (RootBridgeHandle, Temp->Handle);\r
+    }\r
+\r
+    //\r
+    // Remove this node from the linked list\r
+    //\r
+    RemoveEntryList (CurrentLink);\r
+\r
+    if (!IsListEmpty (&Temp->ChildList)) {\r
+      RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);\r
+    }\r
+\r
+    FreePciDevice (Temp);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+DeRegisterPciDevice (\r
+  IN  EFI_HANDLE                     Controller,\r
+  IN  EFI_HANDLE                     Handle\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This function is used to de-register the PCI device from the EFI,\r
+  That includes un-installing PciIo protocol from the specified PCI\r
+  device handle.\r
+\r
+Arguments:\r
+\r
+  Controller   - An efi handle.\r
+  Handle       - An efi handle.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+{\r
+  EFI_PCI_IO_PROTOCOL             *PciIo;\r
+  EFI_STATUS                      Status;\r
+  PCI_IO_DEVICE                   *PciIoDevice;\r
+  PCI_IO_DEVICE                   *Node;\r
+  LIST_ENTRY                      *CurrentLink;\r
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Handle,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  gPciBusDriverBinding.DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);\r
+\r
+    //\r
+    // If it is already de-registered\r
+    //\r
+    if (!PciIoDevice->Registered) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    //\r
+    // If it is PPB, first de-register its children\r
+    //\r
+\r
+    if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
+\r
+      CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
+\r
+      while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {\r
+        Node    = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+        Status  = DeRegisterPciDevice (Controller, Node->Handle);\r
+\r
+        if (EFI_ERROR (Status)) {\r
+          return Status;\r
+        }\r
+\r
+        CurrentLink = CurrentLink->ForwardLink;\r
+      }\r
+    }\r
+    //\r
+    // Uninstall Pccard Hotplug GUID for Pccard device\r
+    //\r
+    UninstallPciHotplugGuid (PciIoDevice);\r
+\r
+    //\r
+    // Close the child handle\r
+    //\r
+    Status = gBS->CloseProtocol (\r
+                    Controller,\r
+                    &gEfiPciRootBridgeIoProtocolGuid,\r
+                    gPciBusDriverBinding.DriverBindingHandle,\r
+                    Handle\r
+                    );\r
+\r
+    //\r
+    // Un-install the device path protocol and pci io protocol\r
+    //\r
+    if (PciIoDevice->BusOverride) {\r
+      Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                      Handle,\r
+                      &gEfiDevicePathProtocolGuid,\r
+                      PciIoDevice->DevicePath,\r
+                      &gEfiPciIoProtocolGuid,\r
+                      &PciIoDevice->PciIo,\r
+                      &gEfiBusSpecificDriverOverrideProtocolGuid,\r
+                      &PciIoDevice->PciDriverOverride,\r
+                      NULL\r
+                      );\r
+    } else {\r
+      Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                      Handle,\r
+                      &gEfiDevicePathProtocolGuid,\r
+                      PciIoDevice->DevicePath,\r
+                      &gEfiPciIoProtocolGuid,\r
+                      &PciIoDevice->PciIo,\r
+                      NULL\r
+                      );\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      gBS->OpenProtocol (\r
+            Controller,\r
+            &gEfiPciRootBridgeIoProtocolGuid,\r
+            (VOID **) &PciRootBridgeIo,\r
+            gPciBusDriverBinding.DriverBindingHandle,\r
+            Handle,\r
+            EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+            );\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // The Device Driver should disable this device after disconnect\r
+    // so the Pci Bus driver will not touch this device any more.\r
+    // Restore the register field to the original value\r
+    //\r
+    PciIoDevice->Registered = FALSE;\r
+    PciIoDevice->Handle     = NULL;\r
+  } else {\r
+\r
+    //\r
+    // Handle may be closed before\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+StartPciDevicesOnBridge (\r
+  IN EFI_HANDLE                          Controller,\r
+  IN PCI_IO_DEVICE                       *RootBridge,\r
+  IN EFI_DEVICE_PATH_PROTOCOL            *RemainingDevicePath,\r
+  IN OUT UINT8                           *NumberOfChildren,\r
+  IN OUT EFI_HANDLE                      *ChildHandleBuffer\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge\r
+\r
+Arguments:\r
+\r
+  Controller          - An efi handle.\r
+  RootBridge          - A pointer to the PCI_IO_DEVICE.\r
+  RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.\r
+  NumberOfChildren    - Children number.\r
+  ChildHandleBuffer   - A pointer to the child handle buffer.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+// TODO:    EFI_NOT_READY - add return value to function comment\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+// TODO:    EFI_UNSUPPORTED - add return value to function comment\r
+// TODO:    EFI_NOT_FOUND - add return value to function comment\r
+{\r
+  PCI_IO_DEVICE             *Temp;\r
+  PCI_IO_DEVICE             *PciIoDevice;\r
+  EFI_DEV_PATH_PTR          Node;\r
+  EFI_DEVICE_PATH_PROTOCOL  *CurrentDevicePath;\r
+  EFI_STATUS                Status;\r
+  LIST_ENTRY                *CurrentLink;\r
+  UINT64                    Supports;\r
+\r
+  CurrentLink = RootBridge->ChildList.ForwardLink;\r
+\r
+  while (CurrentLink && CurrentLink != &RootBridge->ChildList) {\r
+\r
+    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+    if (RemainingDevicePath != NULL) {\r
+\r
+      Node.DevPath = RemainingDevicePath;\r
+\r
+      if (Node.Pci->Device != Temp->DeviceNumber ||\r
+          Node.Pci->Function != Temp->FunctionNumber) {\r
+        CurrentLink = CurrentLink->ForwardLink;\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Check if the device has been assigned with required resource\r
+      //\r
+      if (!Temp->Allocated) {\r
+        return EFI_NOT_READY;\r
+      }\r
+\r
+      //\r
+      // Check if the current node has been registered before\r
+      // If it is not, register it\r
+      //\r
+      if (!Temp->Registered) {\r
+        PciIoDevice = Temp;\r
+\r
+        Status = RegisterPciDevice (\r
+                  Controller,\r
+                  PciIoDevice,\r
+                  NULL\r
+                  );\r
+\r
+      }\r
+\r
+      if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && Temp->Registered) {\r
+        ChildHandleBuffer[*NumberOfChildren] = Temp->Handle;\r
+        (*NumberOfChildren)++;\r
+      }\r
+\r
+      //\r
+      // Get the next device path\r
+      //\r
+      CurrentDevicePath = EfiNextDevicePathNode (RemainingDevicePath);\r
+      if (EfiIsDevicePathEnd (CurrentDevicePath)) {\r
+        return EFI_SUCCESS;\r
+      }\r
+\r
+      //\r
+      // If it is a PPB\r
+      //\r
+      if (!IsListEmpty (&Temp->ChildList)) {\r
+        Status = StartPciDevicesOnBridge (\r
+                  Controller,\r
+                  Temp,\r
+                  CurrentDevicePath,\r
+                  NumberOfChildren,\r
+                  ChildHandleBuffer\r
+                  );\r
+\r
+        Temp->PciIo.Attributes (\r
+                      &(Temp->PciIo),\r
+                      EfiPciIoAttributeOperationSupported,\r
+                      0,\r
+                      &Supports\r
+                      );\r
+        Supports &= EFI_PCI_DEVICE_ENABLE;\r
+        Temp->PciIo.Attributes (\r
+                      &(Temp->PciIo),\r
+                      EfiPciIoAttributeOperationEnable,\r
+                      Supports,\r
+                      NULL\r
+                      );\r
+\r
+        return Status;\r
+      } else {\r
+\r
+        //\r
+        // Currently, the PCI bus driver only support PCI-PCI bridge\r
+        //\r
+        return EFI_UNSUPPORTED;\r
+      }\r
+\r
+    } else {\r
+\r
+      //\r
+      // If remaining device path is NULL,\r
+      // try to enable all the pci devices under this bridge\r
+      //\r
+\r
+      if (!Temp->Registered && Temp->Allocated) {\r
+\r
+        PciIoDevice = Temp;\r
+\r
+        Status = RegisterPciDevice (\r
+                  Controller,\r
+                  PciIoDevice,\r
+                  NULL\r
+                  );\r
+\r
+      }\r
+\r
+      if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && Temp->Registered) {\r
+        ChildHandleBuffer[*NumberOfChildren] = Temp->Handle;\r
+        (*NumberOfChildren)++;\r
+      }\r
+\r
+      if (!IsListEmpty (&Temp->ChildList)) {\r
+        Status = StartPciDevicesOnBridge (\r
+                  Controller,\r
+                  Temp,\r
+                  RemainingDevicePath,\r
+                  NumberOfChildren,\r
+                  ChildHandleBuffer\r
+                  );\r
+\r
+        Temp->PciIo.Attributes (\r
+                      &(Temp->PciIo),\r
+                      EfiPciIoAttributeOperationSupported,\r
+                      0,\r
+                      &Supports\r
+                      );\r
+        Supports &= EFI_PCI_DEVICE_ENABLE;\r
+        Temp->PciIo.Attributes (\r
+                      &(Temp->PciIo),\r
+                      EfiPciIoAttributeOperationEnable,\r
+                      Supports,\r
+                      NULL\r
+                      );\r
+\r
+      }\r
+\r
+      CurrentLink = CurrentLink->ForwardLink;\r
+      continue;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+EFI_STATUS\r
+StartPciDevices (\r
+  IN EFI_HANDLE                         Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL           *RemainingDevicePath\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Start to manage the PCI device according to RemainingDevicePath\r
+  If RemainingDevicePath == NULL, the PCI bus driver will start\r
+  to manage all the PCI devices it found previously\r
+\r
+Arguments:\r
+  Controller          - An efi handle.\r
+  RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+// TODO:    EFI_UNSUPPORTED - add return value to function comment\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+{\r
+  EFI_DEV_PATH_PTR  Node;\r
+  PCI_IO_DEVICE     *RootBridge;\r
+  LIST_ENTRY        *CurrentLink;\r
+\r
+  if (RemainingDevicePath != NULL) {\r
+\r
+    //\r
+    // Check if the RemainingDevicePath is valid\r
+    //\r
+    Node.DevPath = RemainingDevicePath;\r
+    if ((Node.DevPath->Type != HARDWARE_DEVICE_PATH) ||\r
+        ((Node.DevPath->SubType != HW_PCI_DP)         &&\r
+         (DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)))\r
+        ) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+  }\r
+\r
+  CurrentLink = gPciDevicePool.ForwardLink;\r
+\r
+  while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
+\r
+    RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+    //\r
+    // Locate the right root bridge to start\r
+    //\r
+    if (RootBridge->Handle == Controller) {\r
+      StartPciDevicesOnBridge (\r
+        Controller,\r
+        RootBridge,\r
+        RemainingDevicePath,\r
+        NULL,\r
+        NULL\r
+        );\r
+    }\r
+\r
+    CurrentLink = CurrentLink->ForwardLink;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+PCI_IO_DEVICE *\r
+CreateRootBridge (\r
+  IN EFI_HANDLE RootBridgeHandle\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+\r
+Arguments:\r
+  RootBridgeHandle   - An efi handle.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+\r
+  EFI_STATUS                      Status;\r
+  PCI_IO_DEVICE                   *Dev;\r
+  EFI_DEVICE_PATH_PROTOCOL        *ParentDevicePath;\r
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
+\r
+  Dev = NULL;\r
+  Status = gBS->AllocatePool (\r
+                  EfiBootServicesData,\r
+                  sizeof (PCI_IO_DEVICE),\r
+                  (VOID **) &Dev\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  ZeroMem (Dev, sizeof (PCI_IO_DEVICE));\r
+  Dev->Signature  = PCI_IO_DEVICE_SIGNATURE;\r
+  Dev->Handle     = RootBridgeHandle;\r
+  InitializeListHead (&Dev->ChildList);\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  RootBridgeHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &ParentDevicePath,\r
+                  gPciBusDriverBinding.DriverBindingHandle,\r
+                  RootBridgeHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->FreePool (Dev);\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Record the root bridge parent device path\r
+  //\r
+  Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);\r
+\r
+  //\r
+  // Get the pci root bridge io protocol\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  RootBridgeHandle,\r
+                  &gEfiPciRootBridgeIoProtocolGuid,\r
+                  (VOID **) &PciRootBridgeIo,\r
+                  gPciBusDriverBinding.DriverBindingHandle,\r
+                  RootBridgeHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    FreePciDevice (Dev);\r
+    return NULL;\r
+  }\r
+\r
+  Dev->PciRootBridgeIo = PciRootBridgeIo;\r
+\r
+  //\r
+  // Initialize the PCI I/O instance structure\r
+  //\r
+  Status  = InitializePciIoInstance (Dev);\r
+  Status  = InitializePciDriverOverrideInstance (Dev);\r
+\r
+  //\r
+  // Initialize reserved resource list and\r
+  // option rom driver list\r
+  //\r
+  InitializeListHead (&Dev->ReservedResourceList);\r
+  InitializeListHead (&Dev->OptionRomDriverList);\r
+\r
+  return Dev;\r
+}\r
+\r
+PCI_IO_DEVICE *\r
+GetRootBridgeByHandle (\r
+  EFI_HANDLE RootBridgeHandle\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+\r
+Arguments:\r
+\r
+  RootBridgeHandle    - An efi handle.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  PCI_IO_DEVICE   *RootBridgeDev;\r
+  LIST_ENTRY      *CurrentLink;\r
+\r
+  CurrentLink = gPciDevicePool.ForwardLink;\r
+\r
+  while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
+\r
+    RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+    if (RootBridgeDev->Handle == RootBridgeHandle) {\r
+      return RootBridgeDev;\r
+    }\r
+\r
+    CurrentLink = CurrentLink->ForwardLink;\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+BOOLEAN\r
+RootBridgeExisted (\r
+  IN EFI_HANDLE RootBridgeHandle\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This function searches if RootBridgeHandle has already existed\r
+  in current device pool.\r
+\r
+  If so, it means the given root bridge has been already enumerated.\r
+\r
+Arguments:\r
+\r
+  RootBridgeHandle   - An efi handle.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  PCI_IO_DEVICE *Bridge;\r
+\r
+  Bridge = GetRootBridgeByHandle (RootBridgeHandle);\r
+\r
+  if (Bridge != NULL) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+BOOLEAN\r
+PciDeviceExisted (\r
+  IN PCI_IO_DEVICE    *Bridge,\r
+  IN PCI_IO_DEVICE    *PciIoDevice\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+Arguments:\r
+\r
+  Bridge       - A pointer to the PCI_IO_DEVICE.\r
+  PciIoDevice  - A pointer to the PCI_IO_DEVICE.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+\r
+  PCI_IO_DEVICE   *Temp;\r
+  LIST_ENTRY      *CurrentLink;\r
+\r
+  CurrentLink = Bridge->ChildList.ForwardLink;\r
+\r
+  while (CurrentLink && CurrentLink != &Bridge->ChildList) {\r
+\r
+    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+\r
+    if (Temp == PciIoDevice) {\r
+      return TRUE;\r
+    }\r
+\r
+    if (!IsListEmpty (&Temp->ChildList)) {\r
+      if (PciDeviceExisted (Temp, PciIoDevice)) {\r
+        return TRUE;\r
+      }\r
+    }\r
+\r
+    CurrentLink = CurrentLink->ForwardLink;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+PCI_IO_DEVICE *\r
+ActiveVGADeviceOnTheSameSegment (\r
+  IN PCI_IO_DEVICE        *VgaDevice\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+Arguments:\r
+\r
+  VgaDevice    - A pointer to the PCI_IO_DEVICE.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  LIST_ENTRY      *CurrentLink;\r
+  PCI_IO_DEVICE   *Temp;\r
+\r
+  CurrentLink = gPciDevicePool.ForwardLink;\r
+\r
+  while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
+\r
+    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+\r
+    if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {\r
+\r
+      Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
+\r
+      if (Temp != NULL) {\r
+        return Temp;\r
+      }\r
+    }\r
+\r
+    CurrentLink = CurrentLink->ForwardLink;\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+PCI_IO_DEVICE *\r
+ActiveVGADeviceOnTheRootBridge (\r
+  IN PCI_IO_DEVICE        *RootBridge\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+Arguments:\r
+\r
+  RootBridge    - A pointer to the PCI_IO_DEVICE.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  LIST_ENTRY      *CurrentLink;\r
+  PCI_IO_DEVICE   *Temp;\r
+\r
+  CurrentLink = RootBridge->ChildList.ForwardLink;\r
+\r
+  while (CurrentLink && CurrentLink != &RootBridge->ChildList) {\r
+\r
+    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+\r
+    if (IS_PCI_VGA(&Temp->Pci) &&\r
+        (Temp->Attributes &\r
+         (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |\r
+          EFI_PCI_IO_ATTRIBUTE_VGA_IO     |\r
+          EFI_PCI_IO_ATTRIBUTE_VGA_IO_16))) {\r
+      return Temp;\r
+    }\r
+\r
+    if (IS_PCI_BRIDGE (&Temp->Pci)) {\r
+\r
+      Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
+\r
+      if (Temp != NULL) {\r
+        return Temp;\r
+      }\r
+    }\r
+\r
+    CurrentLink = CurrentLink->ForwardLink;\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+EFI_STATUS\r
+GetHpcPciAddress (\r
+  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *PciRootBridgeIo,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL         *HpcDevicePath,\r
+  OUT UINT64                           *PciAddress\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+Arguments:\r
+\r
+  PciRootBridgeIo       - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
+  HpcDevicePath         - A pointer to the EFI_DEVICE_PATH_PROTOCL.\r
+  PciAddress            - A pointer to the pci address.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+// TODO:    EFI_NOT_FOUND - add return value to function comment\r
+// TODO:    EFI_NOT_FOUND - add return value to function comment\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+// TODO:    EFI_NOT_FOUND - add return value to function comment\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL  *CurrentDevicePath;\r
+  EFI_DEV_PATH_PTR          Node;\r
+  LIST_ENTRY                *CurrentLink;\r
+  PCI_IO_DEVICE             *RootBridge;\r
+  EFI_STATUS                Status;\r
+\r
+  CurrentDevicePath = HpcDevicePath;\r
+\r
+  //\r
+  // Get the remaining device path for this PCI device, if it is a PCI device\r
+  //\r
+  while (!EfiIsDevicePathEnd (CurrentDevicePath)) {\r
+\r
+    Node.DevPath = CurrentDevicePath;\r
+\r
+    //\r
+    // Check if it is PCI device Path?\r
+    //\r
+    if ((Node.DevPath->Type != HARDWARE_DEVICE_PATH) ||\r
+        ((Node.DevPath->SubType != HW_PCI_DP)         &&\r
+         (DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)))) {\r
+      CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);\r
+      continue;\r
+    }\r
+\r
+    break;\r
+  }\r
+\r
+  //\r
+  // Check if it is not PCI device path\r
+  //\r
+  if (EfiIsDevicePathEnd (CurrentDevicePath)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  CurrentLink = gPciDevicePool.ForwardLink;\r
+\r
+  while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
+\r
+    RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+    //\r
+    // Locate the right root bridge to start\r
+    //\r
+    if (RootBridge->PciRootBridgeIo == PciRootBridgeIo) {\r
+      Status = GetHpcPciAddressFromRootBridge (\r
+                RootBridge,\r
+                CurrentDevicePath,\r
+                PciAddress\r
+                );\r
+      if (EFI_ERROR (Status)) {\r
+        return EFI_NOT_FOUND;\r
+      }\r
+\r
+      return EFI_SUCCESS;\r
+\r
+    }\r
+\r
+    CurrentLink = CurrentLink->ForwardLink;\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+EFI_STATUS\r
+GetHpcPciAddressFromRootBridge (\r
+  IN  PCI_IO_DEVICE                    *RootBridge,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL         *RemainingDevicePath,\r
+  OUT UINT64                           *PciAddress\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+Arguments:\r
+\r
+  PciRootBridgeIo       - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
+  HpcDevicePath         - A pointer to the EFI_DEVICE_PATH_PROTOCL.\r
+  PciAddress            - A pointer to the pci address.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+// TODO:    RootBridge - add argument and description to function comment\r
+// TODO:    RemainingDevicePath - add argument and description to function comment\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+// TODO:    EFI_NOT_FOUND - add return value to function comment\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+{\r
+  EFI_DEV_PATH_PTR          Node;\r
+  PCI_IO_DEVICE             *Temp;\r
+  EFI_DEVICE_PATH_PROTOCOL  *CurrentDevicePath;\r
+  LIST_ENTRY                *CurrentLink;\r
+  BOOLEAN                   MisMatch;\r
+\r
+  MisMatch          = FALSE;\r
+\r
+  CurrentDevicePath = RemainingDevicePath;\r
+  Node.DevPath      = CurrentDevicePath;\r
+  Temp              = NULL;\r
+\r
+  while (!EfiIsDevicePathEnd (CurrentDevicePath)) {\r
+\r
+    CurrentLink   = RootBridge->ChildList.ForwardLink;\r
+    Node.DevPath  = CurrentDevicePath;\r
+\r
+    while (CurrentLink && CurrentLink != &RootBridge->ChildList) {\r
+      Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+\r
+      if (Node.Pci->Device   == Temp->DeviceNumber &&\r
+          Node.Pci->Function == Temp->FunctionNumber) {\r
+        RootBridge = Temp;\r
+        break;\r
+      }\r
+\r
+      CurrentLink = CurrentLink->ForwardLink;\r
+    }\r
+\r
+    //\r
+    // Check if we find the bridge\r
+    //\r
+    if (CurrentLink == &RootBridge->ChildList) {\r
+\r
+      MisMatch = TRUE;\r
+      break;\r
+\r
+    }\r
+\r
+    CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);\r
+  }\r
+\r
+  if (MisMatch) {\r
+\r
+    CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);\r
+\r
+    if (EfiIsDevicePathEnd (CurrentDevicePath)) {\r
+      *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r