Home | History | Annotate | Download | only in PciBusNoEnumerationDxe
      1 /*++
      2 
      3 Copyright (c) 2005 - 2006, Intel Corporation. All rights reserved.<BR>
      4 This program and the accompanying materials
      5 are licensed and made available under the terms and conditions of the BSD License
      6 which accompanies this distribution.  The full text of the license may be found at
      7 http://opensource.org/licenses/bsd-license.php
      8 
      9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 Module Name:
     13 
     14   PciDeviceSupport.c
     15 
     16 Abstract:
     17 
     18   This file provides routine to support Pci device node manipulation
     19 
     20 Revision History
     21 
     22 --*/
     23 
     24 #include "PciBus.h"
     25 
     26 //
     27 // This device structure is serviced as a header.
     28 // Its Next field points to the first root bridge device node
     29 //
     30 LIST_ENTRY  gPciDevicePool;
     31 
     32 EFI_STATUS
     33 InitializePciDevicePool (
     34   VOID
     35   )
     36 /*++
     37 
     38 Routine Description:
     39 
     40   Initialize the gPciDevicePool
     41 
     42 Arguments:
     43 
     44 Returns:
     45 
     46   None
     47 
     48 --*/
     49 {
     50   InitializeListHead (&gPciDevicePool);
     51 
     52   return EFI_SUCCESS;
     53 }
     54 
     55 EFI_STATUS
     56 InsertRootBridge (
     57   IN PCI_IO_DEVICE *RootBridge
     58   )
     59 /*++
     60 
     61 Routine Description:
     62 
     63   Insert a root bridge into PCI device pool
     64 
     65 Arguments:
     66 
     67   RootBridge    - A pointer to the PCI_IO_DEVICE.
     68 
     69 Returns:
     70 
     71   None
     72 
     73 --*/
     74 {
     75   InsertTailList (&gPciDevicePool, &(RootBridge->Link));
     76 
     77   return EFI_SUCCESS;
     78 }
     79 
     80 EFI_STATUS
     81 InsertPciDevice (
     82   PCI_IO_DEVICE *Bridge,
     83   PCI_IO_DEVICE *PciDeviceNode
     84   )
     85 /*++
     86 
     87 Routine Description:
     88 
     89   This function is used to insert a PCI device node under
     90   a bridge
     91 
     92 Arguments:
     93   Bridge        - A pointer to the PCI_IO_DEVICE.
     94   PciDeviceNode - A pointer to the PCI_IO_DEVICE.
     95 
     96 Returns:
     97 
     98   None
     99 
    100 --*/
    101 
    102 {
    103 
    104   InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link));
    105   PciDeviceNode->Parent = Bridge;
    106 
    107   return EFI_SUCCESS;
    108 }
    109 
    110 EFI_STATUS
    111 DestroyRootBridge (
    112   IN PCI_IO_DEVICE *RootBridge
    113   )
    114 /*++
    115 
    116 Routine Description:
    117 
    118 
    119 Arguments:
    120 
    121   RootBridge   - A pointer to the PCI_IO_DEVICE.
    122 
    123 Returns:
    124 
    125   None
    126 
    127 --*/
    128 {
    129   DestroyPciDeviceTree (RootBridge);
    130 
    131   gBS->FreePool (RootBridge);
    132 
    133   return EFI_SUCCESS;
    134 }
    135 
    136 EFI_STATUS
    137 DestroyPciDeviceTree (
    138   IN PCI_IO_DEVICE *Bridge
    139   )
    140 /*++
    141 
    142 Routine Description:
    143 
    144   Destroy all the pci device node under the bridge.
    145   Bridge itself is not included.
    146 
    147 Arguments:
    148 
    149   Bridge   - A pointer to the PCI_IO_DEVICE.
    150 
    151 Returns:
    152 
    153   None
    154 
    155 --*/
    156 {
    157   LIST_ENTRY  *CurrentLink;
    158   PCI_IO_DEVICE   *Temp;
    159 
    160   while (!IsListEmpty (&Bridge->ChildList)) {
    161 
    162     CurrentLink = Bridge->ChildList.ForwardLink;
    163 
    164     //
    165     // Remove this node from the linked list
    166     //
    167     RemoveEntryList (CurrentLink);
    168 
    169     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
    170 
    171     if (IS_PCI_BRIDGE (&(Temp->Pci))) {
    172       DestroyPciDeviceTree (Temp);
    173     }
    174     gBS->FreePool (Temp);
    175   }
    176 
    177   return EFI_SUCCESS;
    178 }
    179 
    180 EFI_STATUS
    181 DestroyRootBridgeByHandle (
    182   EFI_HANDLE Controller
    183   )
    184 /*++
    185 
    186 Routine Description:
    187 
    188   Destroy all device nodes under the root bridge
    189   specified by Controller.
    190   The root bridge itself is also included.
    191 
    192 Arguments:
    193 
    194   Controller   - An efi handle.
    195 
    196 Returns:
    197 
    198   None
    199 
    200 --*/
    201 {
    202 
    203   LIST_ENTRY  *CurrentLink;
    204   PCI_IO_DEVICE   *Temp;
    205 
    206   CurrentLink = gPciDevicePool.ForwardLink;
    207 
    208   while (CurrentLink && CurrentLink != &gPciDevicePool) {
    209     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
    210 
    211     if (Temp->Handle == Controller) {
    212 
    213       RemoveEntryList (CurrentLink);
    214 
    215       DestroyPciDeviceTree (Temp);
    216 
    217       gBS->FreePool(Temp);
    218 
    219       return EFI_SUCCESS;
    220     }
    221 
    222     CurrentLink = CurrentLink->ForwardLink;
    223   }
    224 
    225   return EFI_NOT_FOUND;
    226 }
    227 
    228 EFI_STATUS
    229 RegisterPciDevice (
    230   IN  EFI_HANDLE                     Controller,
    231   IN  PCI_IO_DEVICE                  *PciIoDevice,
    232   OUT EFI_HANDLE                     *Handle OPTIONAL
    233   )
    234 /*++
    235 
    236 Routine Description:
    237 
    238   This function registers the PCI IO device. It creates a handle for this PCI IO device
    239   (if the handle does not exist), attaches appropriate protocols onto the handle, does
    240   necessary initialization, and sets up parent/child relationship with its bus controller.
    241 
    242 Arguments:
    243 
    244   Controller    - An EFI handle for the PCI bus controller.
    245   PciIoDevice   - A PCI_IO_DEVICE pointer to the PCI IO device to be registered.
    246   Handle        - A pointer to hold the EFI handle for the PCI IO device.
    247 
    248 Returns:
    249 
    250   EFI_SUCCESS   - The PCI device is successfully registered.
    251   Others        - An error occurred when registering the PCI device.
    252 
    253 --*/
    254 {
    255   EFI_STATUS          Status;
    256   UINT8               PciExpressCapRegOffset;
    257 
    258   //
    259   // Install the pciio protocol, device path protocol and
    260   // Bus Specific Driver Override Protocol
    261   //
    262 
    263   if (PciIoDevice->BusOverride) {
    264     Status = gBS->InstallMultipleProtocolInterfaces (
    265                   &PciIoDevice->Handle,
    266                   &gEfiDevicePathProtocolGuid,
    267                   PciIoDevice->DevicePath,
    268                   &gEfiPciIoProtocolGuid,
    269                   &PciIoDevice->PciIo,
    270                   &gEfiBusSpecificDriverOverrideProtocolGuid,
    271                   &PciIoDevice->PciDriverOverride,
    272                   NULL
    273                   );
    274   } else {
    275     Status = gBS->InstallMultipleProtocolInterfaces (
    276                   &PciIoDevice->Handle,
    277                   &gEfiDevicePathProtocolGuid,
    278                   PciIoDevice->DevicePath,
    279                   &gEfiPciIoProtocolGuid,
    280                   &PciIoDevice->PciIo,
    281                   NULL
    282                   );
    283   }
    284 
    285   if (EFI_ERROR (Status)) {
    286     return Status;
    287   } else {
    288     Status = gBS->OpenProtocol (
    289                     Controller,
    290                     &gEfiPciRootBridgeIoProtocolGuid,
    291                     (VOID **)&(PciIoDevice->PciRootBridgeIo),
    292                     gPciBusDriverBinding.DriverBindingHandle,
    293                     PciIoDevice->Handle,
    294                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    295                     );
    296     if (EFI_ERROR (Status)) {
    297       return Status;
    298     }
    299   }
    300 
    301   if (Handle != NULL) {
    302     *Handle = PciIoDevice->Handle;
    303   }
    304 
    305   //
    306   // Detect if PCI Express Device
    307   //
    308   PciExpressCapRegOffset = 0;
    309   Status = LocateCapabilityRegBlock (
    310              PciIoDevice,
    311              EFI_PCI_CAPABILITY_ID_PCIEXP,
    312              &PciExpressCapRegOffset,
    313              NULL
    314              );
    315   if (!EFI_ERROR (Status)) {
    316     PciIoDevice->IsPciExp = TRUE;
    317     DEBUG ((EFI_D_ERROR, "PciExp - %x (B-%x, D-%x, F-%x)\n", PciIoDevice->IsPciExp, PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber));
    318   }
    319 
    320   //
    321   // Indicate the pci device is registered
    322   //
    323   PciIoDevice->Registered = TRUE;
    324 
    325   return EFI_SUCCESS;
    326 }
    327 
    328 
    329 EFI_STATUS
    330 DeRegisterPciDevice (
    331   IN  EFI_HANDLE                     Controller,
    332   IN  EFI_HANDLE                     Handle
    333   )
    334 /*++
    335 
    336 Routine Description:
    337 
    338   This function is used to de-register the PCI device from the EFI,
    339   That includes un-installing PciIo protocol from the specified PCI
    340   device handle.
    341 
    342 Arguments:
    343 
    344   Controller   - An efi handle.
    345   Handle       - An efi handle.
    346 
    347 Returns:
    348 
    349   None
    350 
    351 --*/
    352 {
    353   EFI_PCI_IO_PROTOCOL             *PciIo;
    354   EFI_STATUS                      Status;
    355   PCI_IO_DEVICE                   *PciIoDevice;
    356   PCI_IO_DEVICE                   *Node;
    357   LIST_ENTRY                  *CurrentLink;
    358   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
    359 
    360   Status = gBS->OpenProtocol (
    361                   Handle,
    362                   &gEfiPciIoProtocolGuid,
    363                   (VOID **) &PciIo,
    364                   gPciBusDriverBinding.DriverBindingHandle,
    365                   Controller,
    366                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    367                   );
    368   if (!EFI_ERROR (Status)) {
    369     PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
    370 
    371     //
    372     // If it is already de-registered
    373     //
    374     if (!PciIoDevice->Registered) {
    375       return EFI_SUCCESS;
    376     }
    377 
    378     //
    379     // If it is PPB, first de-register its children
    380     //
    381 
    382     if (IS_PCI_BRIDGE (&(PciIoDevice->Pci))) {
    383 
    384       CurrentLink = PciIoDevice->ChildList.ForwardLink;
    385 
    386       while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {
    387         Node    = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
    388         Status  = DeRegisterPciDevice (Controller, Node->Handle);
    389 
    390         if (EFI_ERROR (Status)) {
    391           return Status;
    392         }
    393 
    394         CurrentLink = CurrentLink->ForwardLink;
    395       }
    396     }
    397 
    398     //
    399     // First disconnect this device
    400     //
    401 //    PciIoDevice->PciIo.Attributes(&(PciIoDevice->PciIo),
    402 //                                    EfiPciIoAttributeOperationDisable,
    403 //                                    EFI_PCI_DEVICE_ENABLE,
    404 //                                    NULL
    405 //                                    );
    406 
    407     //
    408     // Close the child handle
    409     //
    410     Status = gBS->CloseProtocol (
    411                     Controller,
    412                     &gEfiPciRootBridgeIoProtocolGuid,
    413                     gPciBusDriverBinding.DriverBindingHandle,
    414                     Handle
    415                     );
    416 
    417     //
    418     // Un-install the device path protocol and pci io protocol
    419     //
    420     if (PciIoDevice->BusOverride) {
    421       Status = gBS->UninstallMultipleProtocolInterfaces (
    422                       Handle,
    423                       &gEfiDevicePathProtocolGuid,
    424                       PciIoDevice->DevicePath,
    425                       &gEfiPciIoProtocolGuid,
    426                       &PciIoDevice->PciIo,
    427                       &gEfiBusSpecificDriverOverrideProtocolGuid,
    428                       &PciIoDevice->PciDriverOverride,
    429                       NULL
    430                       );
    431     } else {
    432       Status = gBS->UninstallMultipleProtocolInterfaces (
    433                       Handle,
    434                       &gEfiDevicePathProtocolGuid,
    435                       PciIoDevice->DevicePath,
    436                       &gEfiPciIoProtocolGuid,
    437                       &PciIoDevice->PciIo,
    438                       NULL
    439                       );
    440     }
    441 
    442     if (EFI_ERROR (Status)) {
    443       gBS->OpenProtocol (
    444             Controller,
    445             &gEfiPciRootBridgeIoProtocolGuid,
    446             (VOID **) &PciRootBridgeIo,
    447             gPciBusDriverBinding.DriverBindingHandle,
    448             Handle,
    449             EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    450             );
    451       return Status;
    452     }
    453 
    454     //
    455     // The Device Driver should disable this device after disconnect
    456     // so the Pci Bus driver will not touch this device any more.
    457     // Restore the register field to the original value
    458     //
    459     PciIoDevice->Registered = FALSE;
    460     PciIoDevice->Handle     = NULL;
    461   } else {
    462 
    463     //
    464     // Handle may be closed before
    465     //
    466     return EFI_SUCCESS;
    467   }
    468 
    469   return EFI_SUCCESS;
    470 }
    471 
    472 EFI_STATUS
    473 EnableBridgeAttributes (
    474   IN PCI_IO_DEVICE                       *PciIoDevice
    475   )
    476 {
    477   PCI_TYPE01                PciData;
    478 
    479   //
    480   // NOTE: We should not set EFI_PCI_DEVICE_ENABLE for a bridge
    481   //       directly, because some legacy BIOS will NOT assign
    482   //       IO or Memory resource for a bridge who has no child
    483   //       device. So we add check IO or Memory here.
    484   //
    485 
    486   PciIoDevice->PciIo.Pci.Read (
    487                            &PciIoDevice->PciIo,
    488                            EfiPciIoWidthUint8,
    489                            0,
    490                            sizeof (PciData),
    491                            &PciData
    492                            );
    493 
    494   if ((((PciData.Bridge.IoBase & 0xF) == 0) &&
    495         (PciData.Bridge.IoBase != 0 || PciData.Bridge.IoLimit != 0)) ||
    496       (((PciData.Bridge.IoBase & 0xF) == 1) &&
    497         ((PciData.Bridge.IoBase & 0xF0) != 0 || (PciData.Bridge.IoLimit & 0xF0) != 0 || PciData.Bridge.IoBaseUpper16 != 0 || PciData.Bridge.IoLimitUpper16 != 0))) {
    498     PciIoDevice->PciIo.Attributes(
    499                          &(PciIoDevice->PciIo),
    500                          EfiPciIoAttributeOperationEnable,
    501                          (EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
    502                          NULL
    503                          );
    504   }
    505   if ((PciData.Bridge.MemoryBase & 0xFFF0) != 0 || (PciData.Bridge.MemoryLimit & 0xFFF0) != 0) {
    506     PciIoDevice->PciIo.Attributes(
    507                          &(PciIoDevice->PciIo),
    508                          EfiPciIoAttributeOperationEnable,
    509                          (EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
    510                          NULL
    511                          );
    512   }
    513   if ((((PciData.Bridge.PrefetchableMemoryBase & 0xF) == 0) &&
    514         (PciData.Bridge.PrefetchableMemoryBase != 0 || PciData.Bridge.PrefetchableMemoryLimit != 0)) ||
    515       (((PciData.Bridge.PrefetchableMemoryBase & 0xF) == 1) &&
    516         ((PciData.Bridge.PrefetchableMemoryBase & 0xFFF0) != 0 || (PciData.Bridge.PrefetchableMemoryLimit & 0xFFF0) != 0 || PciData.Bridge.PrefetchableBaseUpper32 != 0 || PciData.Bridge.PrefetchableLimitUpper32 != 0))) {
    517     PciIoDevice->PciIo.Attributes(
    518                          &(PciIoDevice->PciIo),
    519                          EfiPciIoAttributeOperationEnable,
    520                          (EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
    521                          NULL
    522                          );
    523   }
    524 
    525   return EFI_SUCCESS;
    526 }
    527 
    528 EFI_STATUS
    529 StartPciDevicesOnBridge (
    530   IN EFI_HANDLE                          Controller,
    531   IN PCI_IO_DEVICE                       *RootBridge,
    532   IN EFI_DEVICE_PATH_PROTOCOL            *RemainingDevicePath
    533   )
    534 /*++
    535 
    536 Routine Description:
    537 
    538   Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge
    539 
    540 Arguments:
    541 
    542   Controller          - An efi handle.
    543   RootBridge          - A pointer to the PCI_IO_DEVICE.
    544   RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.
    545   NumberOfChildren    - Children number.
    546   ChildHandleBuffer   - A pointer to the child handle buffer.
    547 
    548 Returns:
    549 
    550   None
    551 
    552 --*/
    553 {
    554   PCI_IO_DEVICE             *Temp;
    555   PCI_IO_DEVICE             *PciIoDevice;
    556   EFI_DEV_PATH_PTR          Node;
    557   EFI_DEVICE_PATH_PROTOCOL  *CurrentDevicePath;
    558   EFI_STATUS                Status;
    559   LIST_ENTRY            *CurrentLink;
    560 
    561   CurrentLink = RootBridge->ChildList.ForwardLink;
    562 
    563   while (CurrentLink && CurrentLink != &RootBridge->ChildList) {
    564 
    565     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
    566     if (RemainingDevicePath != NULL) {
    567 
    568       Node.DevPath = RemainingDevicePath;
    569 
    570       if (Node.Pci->Device != Temp->DeviceNumber ||
    571           Node.Pci->Function != Temp->FunctionNumber) {
    572         CurrentLink = CurrentLink->ForwardLink;
    573         continue;
    574       }
    575 
    576       //
    577       // Check if the device has been assigned with required resource
    578       //
    579       if (!Temp->Allocated) {
    580         return EFI_NOT_READY;
    581       }
    582 
    583       //
    584       // Check if the current node has been registered before
    585       // If it is not, register it
    586       //
    587       if (!Temp->Registered) {
    588         PciIoDevice = Temp;
    589 
    590         Status = RegisterPciDevice (
    591                   Controller,
    592                   PciIoDevice,
    593                   NULL
    594                   );
    595 
    596       }
    597 
    598       //
    599       // Get the next device path
    600       //
    601       CurrentDevicePath = NextDevicePathNode (RemainingDevicePath);
    602       if (IsDevicePathEnd (CurrentDevicePath)) {
    603         return EFI_SUCCESS;
    604       }
    605 
    606       //
    607       // If it is a PPB
    608       //
    609       if (IS_PCI_BRIDGE (&(Temp->Pci))) {
    610         Status = StartPciDevicesOnBridge (
    611                   Controller,
    612                   Temp,
    613                   CurrentDevicePath
    614                   );
    615         EnableBridgeAttributes (Temp);
    616 
    617         return Status;
    618       } else {
    619 
    620         //
    621         // Currently, the PCI bus driver only support PCI-PCI bridge
    622         //
    623         return EFI_UNSUPPORTED;
    624       }
    625 
    626     } else {
    627 
    628       //
    629       // If remaining device path is NULL,
    630       // try to enable all the pci devices under this bridge
    631       //
    632 
    633       if (!Temp->Registered && Temp->Allocated) {
    634 
    635         PciIoDevice = Temp;
    636 
    637         Status = RegisterPciDevice (
    638                   Controller,
    639                   PciIoDevice,
    640                   NULL
    641                   );
    642 
    643       }
    644 
    645       if (IS_PCI_BRIDGE (&(Temp->Pci))) {
    646         Status = StartPciDevicesOnBridge (
    647                    Controller,
    648                    Temp,
    649                    RemainingDevicePath
    650                    );
    651         EnableBridgeAttributes (Temp);
    652       }
    653 
    654       CurrentLink = CurrentLink->ForwardLink;
    655       continue;
    656     }
    657   }
    658 
    659   return EFI_NOT_FOUND;
    660 }
    661 
    662 EFI_STATUS
    663 StartPciDevices (
    664   IN EFI_HANDLE                         Controller,
    665   IN EFI_DEVICE_PATH_PROTOCOL           *RemainingDevicePath
    666   )
    667 /*++
    668 
    669 Routine Description:
    670 
    671   Start to manage the PCI device according to RemainingDevicePath
    672   If RemainingDevicePath == NULL, the PCI bus driver will start
    673   to manage all the PCI devices it found previously
    674 
    675 Arguments:
    676   Controller          - An efi handle.
    677   RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.
    678 
    679 Returns:
    680 
    681   None
    682 
    683 --*/
    684 {
    685   EFI_DEV_PATH_PTR  Node;
    686   PCI_IO_DEVICE     *RootBridge;
    687   LIST_ENTRY    *CurrentLink;
    688 
    689   if (RemainingDevicePath != NULL) {
    690 
    691     //
    692     // Check if the RemainingDevicePath is valid
    693     //
    694     Node.DevPath = RemainingDevicePath;
    695     if (Node.DevPath->Type != HARDWARE_DEVICE_PATH ||
    696         Node.DevPath->SubType != HW_PCI_DP         ||
    697         DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)
    698         ) {
    699       return EFI_UNSUPPORTED;
    700     }
    701   }
    702 
    703   CurrentLink = gPciDevicePool.ForwardLink;
    704 
    705   while (CurrentLink && CurrentLink != &gPciDevicePool) {
    706 
    707     RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
    708     //
    709     // Locate the right root bridge to start
    710     //
    711     if (RootBridge->Handle == Controller) {
    712       StartPciDevicesOnBridge (
    713         Controller,
    714         RootBridge,
    715         RemainingDevicePath
    716         );
    717     }
    718 
    719     CurrentLink = CurrentLink->ForwardLink;
    720   }
    721 
    722   return EFI_SUCCESS;
    723 }
    724 
    725 PCI_IO_DEVICE *
    726 CreateRootBridge (
    727   IN EFI_HANDLE RootBridgeHandle
    728   )
    729 /*++
    730 
    731 Routine Description:
    732 
    733 
    734 Arguments:
    735   RootBridgeHandle   - An efi handle.
    736 
    737 Returns:
    738 
    739   None
    740 
    741 --*/
    742 {
    743 
    744   EFI_STATUS                      Status;
    745   PCI_IO_DEVICE                   *Dev;
    746 
    747   Dev = NULL;
    748   Status = gBS->AllocatePool (
    749                   EfiBootServicesData,
    750                   sizeof (PCI_IO_DEVICE),
    751                   (VOID **) &Dev
    752                   );
    753 
    754   if (EFI_ERROR (Status)) {
    755     return NULL;
    756   }
    757 
    758   ZeroMem (Dev, sizeof (PCI_IO_DEVICE));
    759   Dev->Signature  = PCI_IO_DEVICE_SIGNATURE;
    760   Dev->Handle     = RootBridgeHandle;
    761   InitializeListHead (&Dev->ChildList);
    762 
    763   return Dev;
    764 }
    765 
    766 PCI_IO_DEVICE *
    767 GetRootBridgeByHandle (
    768   EFI_HANDLE RootBridgeHandle
    769   )
    770 /*++
    771 
    772 Routine Description:
    773 
    774 
    775 Arguments:
    776 
    777   RootBridgeHandle    - An efi handle.
    778 
    779 Returns:
    780 
    781   None
    782 
    783 --*/
    784 {
    785   PCI_IO_DEVICE   *RootBridgeDev;
    786   LIST_ENTRY  *CurrentLink;
    787 
    788   CurrentLink = gPciDevicePool.ForwardLink;
    789 
    790   while (CurrentLink && CurrentLink != &gPciDevicePool) {
    791 
    792     RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
    793     if (RootBridgeDev->Handle == RootBridgeHandle) {
    794       return RootBridgeDev;
    795     }
    796 
    797     CurrentLink = CurrentLink->ForwardLink;
    798   }
    799 
    800   return NULL;
    801 }
    802 
    803 BOOLEAN
    804 RootBridgeExisted (
    805   IN EFI_HANDLE RootBridgeHandle
    806   )
    807 /*++
    808 
    809 Routine Description:
    810 
    811   This function searches if RootBridgeHandle has already existed
    812   in current device pool.
    813 
    814   If so, it means the given root bridge has been already enumerated.
    815 
    816 Arguments:
    817 
    818   RootBridgeHandle   - An efi handle.
    819 
    820 Returns:
    821 
    822   None
    823 
    824 --*/
    825 {
    826   PCI_IO_DEVICE *Bridge;
    827 
    828   Bridge = GetRootBridgeByHandle (RootBridgeHandle);
    829 
    830   if (Bridge != NULL) {
    831     return TRUE;
    832   }
    833 
    834   return FALSE;
    835 }
    836 
    837 BOOLEAN
    838 PciDeviceExisted (
    839   IN PCI_IO_DEVICE    *Bridge,
    840   IN PCI_IO_DEVICE    *PciIoDevice
    841   )
    842 /*++
    843 
    844 Routine Description:
    845 
    846 Arguments:
    847 
    848   Bridge       - A pointer to the PCI_IO_DEVICE.
    849   PciIoDevice  - A pointer to the PCI_IO_DEVICE.
    850 
    851 Returns:
    852 
    853   None
    854 
    855 --*/
    856 {
    857 
    858   PCI_IO_DEVICE   *Temp;
    859   LIST_ENTRY  *CurrentLink;
    860 
    861   CurrentLink = Bridge->ChildList.ForwardLink;
    862 
    863   while (CurrentLink && CurrentLink != &Bridge->ChildList) {
    864 
    865     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
    866 
    867     if (Temp == PciIoDevice) {
    868       return TRUE;
    869     }
    870 
    871     if (!IsListEmpty (&Temp->ChildList)) {
    872       if (PciDeviceExisted (Temp, PciIoDevice)) {
    873         return TRUE;
    874       }
    875     }
    876 
    877     CurrentLink = CurrentLink->ForwardLink;
    878   }
    879 
    880   return FALSE;
    881 }
    882 
    883 PCI_IO_DEVICE *
    884 ActiveVGADeviceOnTheSameSegment (
    885   IN PCI_IO_DEVICE        *VgaDevice
    886   )
    887 /*++
    888 
    889 Routine Description:
    890 
    891 Arguments:
    892 
    893   VgaDevice    - A pointer to the PCI_IO_DEVICE.
    894 
    895 Returns:
    896 
    897   None
    898 
    899 --*/
    900 {
    901   LIST_ENTRY  *CurrentLink;
    902   PCI_IO_DEVICE   *Temp;
    903 
    904   CurrentLink = gPciDevicePool.ForwardLink;
    905 
    906   while (CurrentLink && CurrentLink != &gPciDevicePool) {
    907 
    908     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
    909 
    910     if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {
    911 
    912       Temp = ActiveVGADeviceOnTheRootBridge (Temp);
    913 
    914       if (Temp != NULL) {
    915         return Temp;
    916       }
    917     }
    918 
    919     CurrentLink = CurrentLink->ForwardLink;
    920   }
    921 
    922   return NULL;
    923 }
    924 
    925 PCI_IO_DEVICE *
    926 ActiveVGADeviceOnTheRootBridge (
    927   IN PCI_IO_DEVICE        *RootBridge
    928   )
    929 /*++
    930 
    931 Routine Description:
    932 
    933 Arguments:
    934 
    935   RootBridge    - A pointer to the PCI_IO_DEVICE.
    936 
    937 Returns:
    938 
    939   None
    940 
    941 --*/
    942 {
    943   LIST_ENTRY  *CurrentLink;
    944   PCI_IO_DEVICE   *Temp;
    945 
    946   CurrentLink = RootBridge->ChildList.ForwardLink;
    947 
    948   while (CurrentLink && CurrentLink != &RootBridge->ChildList) {
    949 
    950     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
    951 
    952     if (IS_PCI_VGA(&Temp->Pci) &&
    953         (Temp->Attributes &
    954          (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |
    955           EFI_PCI_IO_ATTRIBUTE_VGA_IO     |
    956           EFI_PCI_IO_ATTRIBUTE_VGA_IO_16))) {
    957       return Temp;
    958     }
    959 
    960     if (IS_PCI_BRIDGE (&Temp->Pci)) {
    961 
    962       Temp = ActiveVGADeviceOnTheRootBridge (Temp);
    963 
    964       if (Temp != NULL) {
    965         return Temp;
    966       }
    967     }
    968 
    969     CurrentLink = CurrentLink->ForwardLink;
    970   }
    971 
    972   return NULL;
    973 }
    974