git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10420 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			880 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			880 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Support functions to connect/disconnect UEFI Driver model Protocol
 | 
						|
 | 
						|
Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
 | 
						|
This program and the accompanying materials
 | 
						|
are licensed and made available under the terms and conditions of the BSD License
 | 
						|
which accompanies this distribution.  The full text of the license may be found at
 | 
						|
http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "DxeMain.h"
 | 
						|
#include "Handle.h"
 | 
						|
 | 
						|
 | 
						|
//
 | 
						|
// Driver Support Functions
 | 
						|
//
 | 
						|
/**
 | 
						|
  Connects one or more drivers to a controller.
 | 
						|
 | 
						|
  @param  ControllerHandle                      Handle of the controller to be
 | 
						|
                                                connected.
 | 
						|
  @param  DriverImageHandle                     DriverImageHandle A pointer to an
 | 
						|
                                                ordered list of driver image
 | 
						|
                                                handles.
 | 
						|
  @param  RemainingDevicePath                   RemainingDevicePath A pointer to
 | 
						|
                                                the device path that specifies a
 | 
						|
                                                child of the controller specified
 | 
						|
                                                by ControllerHandle.
 | 
						|
  @param  Recursive                             Whether the function would be
 | 
						|
                                                called recursively or not.
 | 
						|
 | 
						|
  @return Status code.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CoreConnectController (
 | 
						|
  IN  EFI_HANDLE                ControllerHandle,
 | 
						|
  IN  EFI_HANDLE                *DriverImageHandle    OPTIONAL,
 | 
						|
  IN  EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath  OPTIONAL,
 | 
						|
  IN  BOOLEAN                   Recursive
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                           Status;
 | 
						|
  EFI_STATUS                           ReturnStatus;
 | 
						|
  IHANDLE                              *Handle;
 | 
						|
  PROTOCOL_INTERFACE                   *Prot;
 | 
						|
  LIST_ENTRY                           *Link;
 | 
						|
  LIST_ENTRY                           *ProtLink;
 | 
						|
  OPEN_PROTOCOL_DATA                   *OpenData;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL             *AlignedRemainingDevicePath;
 | 
						|
  EFI_HANDLE                           *ChildHandleBuffer;
 | 
						|
  UINTN                                ChildHandleCount;
 | 
						|
  UINTN                                Index;
 | 
						|
 | 
						|
  //
 | 
						|
  // Make sure ControllerHandle is valid
 | 
						|
  //
 | 
						|
  Status = CoreValidateHandle (ControllerHandle);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Handle = ControllerHandle;
 | 
						|
 | 
						|
  //
 | 
						|
  // Make a copy of RemainingDevicePath to guanatee it is aligned
 | 
						|
  //
 | 
						|
  AlignedRemainingDevicePath = NULL;
 | 
						|
  if (RemainingDevicePath != NULL) {
 | 
						|
    AlignedRemainingDevicePath = DuplicateDevicePath (RemainingDevicePath);
 | 
						|
 | 
						|
    if (AlignedRemainingDevicePath == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Connect all drivers to ControllerHandle
 | 
						|
  // If CoreConnectSingleController returns EFI_NOT_READY, then the number of
 | 
						|
  // Driver Binding Protocols in the handle database has increased during the call
 | 
						|
  // so the connect operation must be restarted
 | 
						|
  //
 | 
						|
  do {
 | 
						|
    ReturnStatus = CoreConnectSingleController (
 | 
						|
                     ControllerHandle,
 | 
						|
                     DriverImageHandle,
 | 
						|
                     AlignedRemainingDevicePath
 | 
						|
                     );
 | 
						|
  } while (ReturnStatus == EFI_NOT_READY);
 | 
						|
 | 
						|
  //
 | 
						|
  // Free the aligned copy of RemainingDevicePath
 | 
						|
  //
 | 
						|
  if (AlignedRemainingDevicePath != NULL) {
 | 
						|
    CoreFreePool (AlignedRemainingDevicePath);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If recursive, then connect all drivers to all of ControllerHandle's children
 | 
						|
  //
 | 
						|
  if (Recursive) {
 | 
						|
    //
 | 
						|
    // Acquire the protocol lock on the handle database so the child handles can be collected
 | 
						|
    //
 | 
						|
    CoreAcquireProtocolLock ();
 | 
						|
 | 
						|
    //
 | 
						|
    // Make sure the DriverBindingHandle is valid
 | 
						|
    //
 | 
						|
    Status = CoreValidateHandle (ControllerHandle);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      //
 | 
						|
      // Release the protocol lock on the handle database
 | 
						|
      //
 | 
						|
      CoreReleaseProtocolLock ();
 | 
						|
 | 
						|
      return ReturnStatus;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    //
 | 
						|
    // Count ControllerHandle's children
 | 
						|
    //
 | 
						|
    for (Link = Handle->Protocols.ForwardLink, ChildHandleCount = 0; Link != &Handle->Protocols; Link = Link->ForwardLink) {
 | 
						|
      Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
 | 
						|
      for (ProtLink = Prot->OpenList.ForwardLink;
 | 
						|
          ProtLink != &Prot->OpenList;
 | 
						|
          ProtLink = ProtLink->ForwardLink) {
 | 
						|
        OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
 | 
						|
        if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
 | 
						|
          ChildHandleCount++;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Allocate a handle buffer for ControllerHandle's children
 | 
						|
    //
 | 
						|
    ChildHandleBuffer = AllocatePool (ChildHandleCount * sizeof(EFI_HANDLE));
 | 
						|
    if (ChildHandleBuffer == NULL) {
 | 
						|
      CoreReleaseProtocolLock ();
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Fill in a handle buffer with ControllerHandle's children
 | 
						|
    //
 | 
						|
    for (Link = Handle->Protocols.ForwardLink, ChildHandleCount = 0; Link != &Handle->Protocols; Link = Link->ForwardLink) {
 | 
						|
      Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
 | 
						|
      for (ProtLink = Prot->OpenList.ForwardLink;
 | 
						|
          ProtLink != &Prot->OpenList;
 | 
						|
          ProtLink = ProtLink->ForwardLink) {
 | 
						|
        OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
 | 
						|
        if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
 | 
						|
          ChildHandleBuffer[ChildHandleCount] = OpenData->ControllerHandle;
 | 
						|
          ChildHandleCount++;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Release the protocol lock on the handle database
 | 
						|
    //
 | 
						|
    CoreReleaseProtocolLock ();
 | 
						|
 | 
						|
    //
 | 
						|
    // Recursively connect each child handle
 | 
						|
    //
 | 
						|
    for (Index = 0; Index < ChildHandleCount; Index++) {
 | 
						|
      CoreConnectController (
 | 
						|
        ChildHandleBuffer[Index],
 | 
						|
        NULL,
 | 
						|
        NULL,
 | 
						|
        TRUE
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Free the handle buffer of ControllerHandle's children
 | 
						|
    //
 | 
						|
    CoreFreePool (ChildHandleBuffer);
 | 
						|
  }
 | 
						|
 | 
						|
  return ReturnStatus;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Add Driver Binding Protocols from Context Driver Image Handles to sorted
 | 
						|
  Driver Binding Protocol list.
 | 
						|
 | 
						|
  @param  DriverBindingHandle                   Handle of the driver binding
 | 
						|
                                                protocol.
 | 
						|
  @param  NumberOfSortedDriverBindingProtocols  Number Of sorted driver binding
 | 
						|
                                                protocols
 | 
						|
  @param  SortedDriverBindingProtocols          The sorted protocol list.
 | 
						|
  @param  DriverBindingHandleCount              Driver Binding Handle Count.
 | 
						|
  @param  DriverBindingHandleBuffer             The buffer of driver binding
 | 
						|
                                                protocol to be modified.
 | 
						|
  @param  IsImageHandle                         Indicate whether
 | 
						|
                                                DriverBindingHandle is an image
 | 
						|
                                                handle
 | 
						|
 | 
						|
  @return None.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
AddSortedDriverBindingProtocol (
 | 
						|
  IN      EFI_HANDLE                   DriverBindingHandle,
 | 
						|
  IN OUT  UINTN                        *NumberOfSortedDriverBindingProtocols,
 | 
						|
  IN OUT  EFI_DRIVER_BINDING_PROTOCOL  **SortedDriverBindingProtocols,
 | 
						|
  IN      UINTN                        DriverBindingHandleCount,
 | 
						|
  IN OUT  EFI_HANDLE                   *DriverBindingHandleBuffer,
 | 
						|
  IN      BOOLEAN                      IsImageHandle
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                   Status;
 | 
						|
  EFI_DRIVER_BINDING_PROTOCOL  *DriverBinding;
 | 
						|
  UINTN                        Index;
 | 
						|
 | 
						|
  //
 | 
						|
  // Make sure the DriverBindingHandle is valid
 | 
						|
  //
 | 
						|
  Status = CoreValidateHandle (DriverBindingHandle);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If IsImageHandle is TRUE, then DriverBindingHandle is an image handle
 | 
						|
  // Find all the DriverBindingHandles associated with that image handle and add them to the sorted list
 | 
						|
  //
 | 
						|
  if (IsImageHandle) {
 | 
						|
    //
 | 
						|
    // Loop through all the Driver Binding Handles
 | 
						|
    //
 | 
						|
    for (Index = 0; Index < DriverBindingHandleCount; Index++) {
 | 
						|
      //
 | 
						|
      // Retrieve the Driver Binding Protocol associated with each Driver Binding Handle
 | 
						|
      //
 | 
						|
      Status = CoreHandleProtocol (
 | 
						|
                DriverBindingHandleBuffer[Index],
 | 
						|
                &gEfiDriverBindingProtocolGuid,
 | 
						|
                (VOID **) &DriverBinding
 | 
						|
                );
 | 
						|
      if (EFI_ERROR (Status) || DriverBinding == NULL) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // If the ImageHandle associated with DriverBinding matches DriverBindingHandle,
 | 
						|
      // then add the DriverBindingProtocol[Index] to the sorted list
 | 
						|
      //
 | 
						|
      if (DriverBinding->ImageHandle == DriverBindingHandle) {
 | 
						|
        AddSortedDriverBindingProtocol (
 | 
						|
          DriverBindingHandleBuffer[Index],
 | 
						|
          NumberOfSortedDriverBindingProtocols,
 | 
						|
          SortedDriverBindingProtocols,
 | 
						|
          DriverBindingHandleCount,
 | 
						|
          DriverBindingHandleBuffer,
 | 
						|
          FALSE
 | 
						|
          );
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Retrieve the Driver Binding Protocol from DriverBindingHandle
 | 
						|
  //
 | 
						|
  Status = CoreHandleProtocol(
 | 
						|
             DriverBindingHandle,
 | 
						|
             &gEfiDriverBindingProtocolGuid,
 | 
						|
             (VOID **) &DriverBinding
 | 
						|
             );
 | 
						|
  //
 | 
						|
  // If DriverBindingHandle does not support the Driver Binding Protocol then return
 | 
						|
  //
 | 
						|
  if (EFI_ERROR (Status) || DriverBinding == NULL) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // See if DriverBinding is already in the sorted list
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < *NumberOfSortedDriverBindingProtocols && Index < DriverBindingHandleCount; Index++) {
 | 
						|
    if (DriverBinding == SortedDriverBindingProtocols[Index]) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Add DriverBinding to the end of the list
 | 
						|
  //
 | 
						|
  if (*NumberOfSortedDriverBindingProtocols < DriverBindingHandleCount) {
 | 
						|
    SortedDriverBindingProtocols[*NumberOfSortedDriverBindingProtocols] = DriverBinding;
 | 
						|
  }
 | 
						|
  *NumberOfSortedDriverBindingProtocols = *NumberOfSortedDriverBindingProtocols + 1;
 | 
						|
 | 
						|
  //
 | 
						|
  // Mark the cooresponding handle in DriverBindingHandleBuffer as used
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < DriverBindingHandleCount; Index++) {
 | 
						|
    if (DriverBindingHandleBuffer[Index] == DriverBindingHandle) {
 | 
						|
      DriverBindingHandleBuffer[Index] = NULL;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Connects a controller to a driver.
 | 
						|
 | 
						|
  @param  ControllerHandle                      Handle of the controller to be
 | 
						|
                                                connected.
 | 
						|
  @param  ContextDriverImageHandles             DriverImageHandle A pointer to an
 | 
						|
                                                ordered list of driver image
 | 
						|
                                                handles.
 | 
						|
  @param  RemainingDevicePath                   RemainingDevicePath A pointer to
 | 
						|
                                                the device path that specifies a
 | 
						|
                                                child  of the controller
 | 
						|
                                                specified by ControllerHandle.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS                           One or more drivers were
 | 
						|
                                                connected to ControllerHandle.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES                  No enough system resources to
 | 
						|
                                                complete the request.
 | 
						|
  @retval EFI_NOT_FOUND                         No drivers were connected to
 | 
						|
                                                ControllerHandle.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
CoreConnectSingleController (
 | 
						|
  IN  EFI_HANDLE                ControllerHandle,
 | 
						|
  IN  EFI_HANDLE                *ContextDriverImageHandles OPTIONAL,
 | 
						|
  IN  EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath       OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                                 Status;
 | 
						|
  UINTN                                      Index;
 | 
						|
  EFI_HANDLE                                 DriverImageHandle;
 | 
						|
  EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL      *PlatformDriverOverride;
 | 
						|
  EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL  *BusSpecificDriverOverride;
 | 
						|
  UINTN                                      DriverBindingHandleCount;
 | 
						|
  EFI_HANDLE                                 *DriverBindingHandleBuffer;
 | 
						|
  UINTN                                      NewDriverBindingHandleCount;
 | 
						|
  EFI_HANDLE                                 *NewDriverBindingHandleBuffer;
 | 
						|
  EFI_DRIVER_BINDING_PROTOCOL                *DriverBinding;
 | 
						|
  UINTN                                      NumberOfSortedDriverBindingProtocols;
 | 
						|
  EFI_DRIVER_BINDING_PROTOCOL                **SortedDriverBindingProtocols;
 | 
						|
  UINT32                                     HighestVersion;
 | 
						|
  UINTN                                      HighestIndex;
 | 
						|
  UINTN                                      SortIndex;
 | 
						|
  BOOLEAN                                    OneStarted;
 | 
						|
  BOOLEAN                                    DriverFound;
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize local variables
 | 
						|
  //
 | 
						|
  DriverBindingHandleCount              = 0;
 | 
						|
  DriverBindingHandleBuffer             = NULL;
 | 
						|
  NumberOfSortedDriverBindingProtocols  = 0;
 | 
						|
  SortedDriverBindingProtocols          = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get list of all Driver Binding Protocol Instances
 | 
						|
  //
 | 
						|
  Status = CoreLocateHandleBuffer (
 | 
						|
             ByProtocol,
 | 
						|
             &gEfiDriverBindingProtocolGuid,
 | 
						|
             NULL,
 | 
						|
             &DriverBindingHandleCount,
 | 
						|
             &DriverBindingHandleBuffer
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status) || (DriverBindingHandleCount == 0)) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate a duplicate array for the sorted Driver Binding Protocol Instances
 | 
						|
  //
 | 
						|
  SortedDriverBindingProtocols = AllocatePool (sizeof (VOID *) * DriverBindingHandleCount);
 | 
						|
  if (SortedDriverBindingProtocols == NULL) {
 | 
						|
    CoreFreePool (DriverBindingHandleBuffer);
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Add Driver Binding Protocols from Context Driver Image Handles first
 | 
						|
  //
 | 
						|
  if (ContextDriverImageHandles != NULL) {
 | 
						|
    for (Index = 0; ContextDriverImageHandles[Index] != NULL; Index++) {
 | 
						|
      AddSortedDriverBindingProtocol (
 | 
						|
        ContextDriverImageHandles[Index],
 | 
						|
        &NumberOfSortedDriverBindingProtocols,
 | 
						|
        SortedDriverBindingProtocols,
 | 
						|
        DriverBindingHandleCount,
 | 
						|
        DriverBindingHandleBuffer,
 | 
						|
        FALSE
 | 
						|
        );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Add the Platform Driver Override Protocol drivers for ControllerHandle next
 | 
						|
  //
 | 
						|
  Status = CoreLocateProtocol (
 | 
						|
             &gEfiPlatformDriverOverrideProtocolGuid,
 | 
						|
             NULL,
 | 
						|
             (VOID **) &PlatformDriverOverride
 | 
						|
             );
 | 
						|
  if (!EFI_ERROR (Status) && (PlatformDriverOverride != NULL)) {
 | 
						|
    DriverImageHandle = NULL;
 | 
						|
    do {
 | 
						|
      Status = PlatformDriverOverride->GetDriver (
 | 
						|
                                         PlatformDriverOverride,
 | 
						|
                                         ControllerHandle,
 | 
						|
                                         &DriverImageHandle
 | 
						|
                                         );
 | 
						|
      if (!EFI_ERROR (Status)) {
 | 
						|
        AddSortedDriverBindingProtocol (
 | 
						|
          DriverImageHandle,
 | 
						|
          &NumberOfSortedDriverBindingProtocols,
 | 
						|
          SortedDriverBindingProtocols,
 | 
						|
          DriverBindingHandleCount,
 | 
						|
          DriverBindingHandleBuffer,
 | 
						|
          TRUE
 | 
						|
          );
 | 
						|
      }
 | 
						|
    } while (!EFI_ERROR (Status));
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the Bus Specific Driver Override Protocol instance on the Controller Handle
 | 
						|
  //
 | 
						|
  Status = CoreHandleProtocol (
 | 
						|
             ControllerHandle,
 | 
						|
             &gEfiBusSpecificDriverOverrideProtocolGuid,
 | 
						|
             (VOID **) &BusSpecificDriverOverride
 | 
						|
             );
 | 
						|
  if (!EFI_ERROR (Status) && (BusSpecificDriverOverride != NULL)) {
 | 
						|
    DriverImageHandle = NULL;
 | 
						|
    do {
 | 
						|
      Status = BusSpecificDriverOverride->GetDriver (
 | 
						|
                                            BusSpecificDriverOverride,
 | 
						|
                                            &DriverImageHandle
 | 
						|
                                            );
 | 
						|
      if (!EFI_ERROR (Status)) {
 | 
						|
        AddSortedDriverBindingProtocol (
 | 
						|
          DriverImageHandle,
 | 
						|
          &NumberOfSortedDriverBindingProtocols,
 | 
						|
          SortedDriverBindingProtocols,
 | 
						|
          DriverBindingHandleCount,
 | 
						|
          DriverBindingHandleBuffer,
 | 
						|
          TRUE
 | 
						|
          );
 | 
						|
      }
 | 
						|
    } while (!EFI_ERROR (Status));
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Then add all the remaining Driver Binding Protocols
 | 
						|
  //
 | 
						|
  SortIndex = NumberOfSortedDriverBindingProtocols;
 | 
						|
  for (Index = 0; Index < DriverBindingHandleCount; Index++) {
 | 
						|
    AddSortedDriverBindingProtocol (
 | 
						|
      DriverBindingHandleBuffer[Index],
 | 
						|
      &NumberOfSortedDriverBindingProtocols,
 | 
						|
      SortedDriverBindingProtocols,
 | 
						|
      DriverBindingHandleCount,
 | 
						|
      DriverBindingHandleBuffer,
 | 
						|
      FALSE
 | 
						|
      );
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Free the Driver Binding Handle Buffer
 | 
						|
  //
 | 
						|
  CoreFreePool (DriverBindingHandleBuffer);
 | 
						|
 | 
						|
  //
 | 
						|
  // If the number of Driver Binding Protocols has increased since this function started, then return
 | 
						|
  // EFI_NOT_READY, so it will be restarted
 | 
						|
  //
 | 
						|
  Status = CoreLocateHandleBuffer (
 | 
						|
             ByProtocol,
 | 
						|
             &gEfiDriverBindingProtocolGuid,
 | 
						|
             NULL,
 | 
						|
             &NewDriverBindingHandleCount,
 | 
						|
             &NewDriverBindingHandleBuffer
 | 
						|
             );
 | 
						|
  CoreFreePool (NewDriverBindingHandleBuffer);
 | 
						|
  if (NewDriverBindingHandleCount > DriverBindingHandleCount) {
 | 
						|
    //
 | 
						|
    // Free any buffers that were allocated with AllocatePool()
 | 
						|
    //
 | 
						|
    CoreFreePool (SortedDriverBindingProtocols);
 | 
						|
 | 
						|
    return EFI_NOT_READY;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Sort the remaining DriverBinding Protocol based on their Version field from
 | 
						|
  // highest to lowest.
 | 
						|
  //
 | 
						|
  for ( ; SortIndex < NumberOfSortedDriverBindingProtocols; SortIndex++) {
 | 
						|
    HighestVersion = SortedDriverBindingProtocols[SortIndex]->Version;
 | 
						|
    HighestIndex   = SortIndex;
 | 
						|
    for (Index = SortIndex + 1; Index < NumberOfSortedDriverBindingProtocols; Index++) {
 | 
						|
      if (SortedDriverBindingProtocols[Index]->Version > HighestVersion) {
 | 
						|
        HighestVersion = SortedDriverBindingProtocols[Index]->Version;
 | 
						|
        HighestIndex   = Index;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (SortIndex != HighestIndex) {
 | 
						|
      DriverBinding = SortedDriverBindingProtocols[SortIndex];
 | 
						|
      SortedDriverBindingProtocols[SortIndex] = SortedDriverBindingProtocols[HighestIndex];
 | 
						|
      SortedDriverBindingProtocols[HighestIndex] = DriverBinding;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Loop until no more drivers can be started on ControllerHandle
 | 
						|
  //
 | 
						|
  OneStarted = FALSE;
 | 
						|
  do {
 | 
						|
 | 
						|
    //
 | 
						|
    // Loop through the sorted Driver Binding Protocol Instances in order, and see if
 | 
						|
    // any of the Driver Binding Protocols support the controller specified by
 | 
						|
    // ControllerHandle.
 | 
						|
    //
 | 
						|
    DriverBinding = NULL;
 | 
						|
    DriverFound = FALSE;
 | 
						|
    for (Index = 0; (Index < NumberOfSortedDriverBindingProtocols) && !DriverFound; Index++) {
 | 
						|
      if (SortedDriverBindingProtocols[Index] != NULL) {
 | 
						|
        DriverBinding = SortedDriverBindingProtocols[Index];
 | 
						|
        PERF_START (DriverBinding->DriverBindingHandle, "DB:Support:", NULL, 0);
 | 
						|
        Status = DriverBinding->Supported(
 | 
						|
                                  DriverBinding,
 | 
						|
                                  ControllerHandle,
 | 
						|
                                  RemainingDevicePath
 | 
						|
                                  );
 | 
						|
        PERF_END (DriverBinding->DriverBindingHandle, "DB:Support:", NULL, 0);
 | 
						|
        if (!EFI_ERROR (Status)) {
 | 
						|
          SortedDriverBindingProtocols[Index] = NULL;
 | 
						|
          DriverFound = TRUE;
 | 
						|
 | 
						|
          //
 | 
						|
          // A driver was found that supports ControllerHandle, so attempt to start the driver
 | 
						|
          // on ControllerHandle.
 | 
						|
          //
 | 
						|
          PERF_START (DriverBinding->DriverBindingHandle, "DB:Start:", NULL, 0);
 | 
						|
          Status = DriverBinding->Start (
 | 
						|
                                    DriverBinding,
 | 
						|
                                    ControllerHandle,
 | 
						|
                                    RemainingDevicePath
 | 
						|
                                    );
 | 
						|
          PERF_END (DriverBinding->DriverBindingHandle, "DB:Start:", NULL, 0);
 | 
						|
 | 
						|
          if (!EFI_ERROR (Status)) {
 | 
						|
            //
 | 
						|
            // The driver was successfully started on ControllerHandle, so set a flag
 | 
						|
            //
 | 
						|
            OneStarted = TRUE;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } while (DriverFound);
 | 
						|
 | 
						|
  //
 | 
						|
  // Free any buffers that were allocated with AllocatePool()
 | 
						|
  //
 | 
						|
  CoreFreePool (SortedDriverBindingProtocols);
 | 
						|
 | 
						|
  //
 | 
						|
  // If at least one driver was started on ControllerHandle, then return EFI_SUCCESS.
 | 
						|
  //
 | 
						|
  if (OneStarted) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If no drivers started and RemainingDevicePath is an End Device Path Node, then return EFI_SUCCESS
 | 
						|
  //
 | 
						|
  if (RemainingDevicePath != NULL) {
 | 
						|
    if (IsDevicePathEnd (RemainingDevicePath)) {
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Otherwise, no drivers were started on ControllerHandle, so return EFI_NOT_FOUND
 | 
						|
  //
 | 
						|
  return EFI_NOT_FOUND;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Disonnects a controller from a driver
 | 
						|
 | 
						|
  @param  ControllerHandle                      ControllerHandle The handle of
 | 
						|
                                                the controller from which
 | 
						|
                                                driver(s)  are to be
 | 
						|
                                                disconnected.
 | 
						|
  @param  DriverImageHandle                     DriverImageHandle The driver to
 | 
						|
                                                disconnect from ControllerHandle.
 | 
						|
  @param  ChildHandle                           ChildHandle The handle of the
 | 
						|
                                                child to destroy.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS                           One or more drivers were
 | 
						|
                                                disconnected from the controller.
 | 
						|
  @retval EFI_SUCCESS                           On entry, no drivers are managing
 | 
						|
                                                ControllerHandle.
 | 
						|
  @retval EFI_SUCCESS                           DriverImageHandle is not NULL,
 | 
						|
                                                and on entry DriverImageHandle is
 | 
						|
                                                not managing ControllerHandle.
 | 
						|
  @retval EFI_INVALID_PARAMETER                 ControllerHandle is not a valid
 | 
						|
                                                EFI_HANDLE.
 | 
						|
  @retval EFI_INVALID_PARAMETER                 DriverImageHandle is not NULL,
 | 
						|
                                                and it is not a valid EFI_HANDLE.
 | 
						|
  @retval EFI_INVALID_PARAMETER                 ChildHandle is not NULL, and it
 | 
						|
                                                is not a valid EFI_HANDLE.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES                  There are not enough resources
 | 
						|
                                                available to disconnect any
 | 
						|
                                                drivers from ControllerHandle.
 | 
						|
  @retval EFI_DEVICE_ERROR                      The controller could not be
 | 
						|
                                                disconnected because of a device
 | 
						|
                                                error.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CoreDisconnectController (
 | 
						|
  IN  EFI_HANDLE  ControllerHandle,
 | 
						|
  IN  EFI_HANDLE  DriverImageHandle  OPTIONAL,
 | 
						|
  IN  EFI_HANDLE  ChildHandle        OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                          Status;
 | 
						|
  IHANDLE                             *Handle;
 | 
						|
  EFI_HANDLE                          *DriverImageHandleBuffer;
 | 
						|
  EFI_HANDLE                          *ChildBuffer;
 | 
						|
  UINTN                               Index;
 | 
						|
  UINTN                               HandleIndex;
 | 
						|
  UINTN                               DriverImageHandleCount;
 | 
						|
  UINTN                               ChildrenToStop;
 | 
						|
  UINTN                               ChildBufferCount;
 | 
						|
  UINTN                               StopCount;
 | 
						|
  BOOLEAN                             Duplicate;
 | 
						|
  BOOLEAN                             ChildHandleValid;
 | 
						|
  BOOLEAN                             DriverImageHandleValid;
 | 
						|
  LIST_ENTRY                          *Link;
 | 
						|
  LIST_ENTRY                          *ProtLink;
 | 
						|
  OPEN_PROTOCOL_DATA                  *OpenData;
 | 
						|
  PROTOCOL_INTERFACE                  *Prot;
 | 
						|
  EFI_DRIVER_BINDING_PROTOCOL         *DriverBinding;
 | 
						|
 | 
						|
  //
 | 
						|
  // Make sure ControllerHandle is valid
 | 
						|
  //
 | 
						|
  Status = CoreValidateHandle (ControllerHandle);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Make sure ChildHandle is valid if it is not NULL
 | 
						|
  //
 | 
						|
  if (ChildHandle != NULL) {
 | 
						|
    Status = CoreValidateHandle (ChildHandle);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Handle = ControllerHandle;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get list of drivers that are currently managing ControllerHandle
 | 
						|
  //
 | 
						|
  DriverImageHandleBuffer = NULL;
 | 
						|
  DriverImageHandleCount  = 1;
 | 
						|
 | 
						|
  if (DriverImageHandle == NULL) {
 | 
						|
    //
 | 
						|
    // Look at each protocol interface for a match
 | 
						|
    //
 | 
						|
    DriverImageHandleCount = 0;
 | 
						|
 | 
						|
    CoreAcquireProtocolLock ();
 | 
						|
    for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
 | 
						|
      Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
 | 
						|
      for (ProtLink = Prot->OpenList.ForwardLink;
 | 
						|
           ProtLink != &Prot->OpenList;
 | 
						|
           ProtLink = ProtLink->ForwardLink) {
 | 
						|
        OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
 | 
						|
        if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
 | 
						|
          DriverImageHandleCount++;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    CoreReleaseProtocolLock ();
 | 
						|
 | 
						|
    //
 | 
						|
    // If there are no drivers managing this controller, then return EFI_SUCCESS
 | 
						|
    //
 | 
						|
    if (DriverImageHandleCount == 0) {
 | 
						|
      Status = EFI_SUCCESS;
 | 
						|
      goto Done;
 | 
						|
    }
 | 
						|
 | 
						|
    DriverImageHandleBuffer = AllocatePool (sizeof (EFI_HANDLE) * DriverImageHandleCount);
 | 
						|
    if (DriverImageHandleBuffer == NULL) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto Done;
 | 
						|
    }
 | 
						|
 | 
						|
    DriverImageHandleCount = 0;
 | 
						|
 | 
						|
    CoreAcquireProtocolLock ();
 | 
						|
    for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
 | 
						|
      Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
 | 
						|
      for (ProtLink = Prot->OpenList.ForwardLink;
 | 
						|
           ProtLink != &Prot->OpenList;
 | 
						|
           ProtLink = ProtLink->ForwardLink) {
 | 
						|
        OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
 | 
						|
        if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
 | 
						|
          Duplicate = FALSE;
 | 
						|
          for (Index = 0; Index< DriverImageHandleCount; Index++) {
 | 
						|
            if (DriverImageHandleBuffer[Index] == OpenData->AgentHandle) {
 | 
						|
              Duplicate = TRUE;
 | 
						|
              break;
 | 
						|
            }
 | 
						|
          }
 | 
						|
          if (!Duplicate) {
 | 
						|
            DriverImageHandleBuffer[DriverImageHandleCount] = OpenData->AgentHandle;
 | 
						|
            DriverImageHandleCount++;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    CoreReleaseProtocolLock ();
 | 
						|
  }
 | 
						|
 | 
						|
  StopCount = 0;
 | 
						|
  for (HandleIndex = 0; HandleIndex < DriverImageHandleCount; HandleIndex++) {
 | 
						|
 | 
						|
    if (DriverImageHandleBuffer != NULL) {
 | 
						|
      DriverImageHandle = DriverImageHandleBuffer[HandleIndex];
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Get the Driver Binding Protocol of the driver that is managing this controller
 | 
						|
    //
 | 
						|
    Status = CoreHandleProtocol (
 | 
						|
               DriverImageHandle,
 | 
						|
               &gEfiDriverBindingProtocolGuid,
 | 
						|
               (VOID **)&DriverBinding
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status) || DriverBinding == NULL) {
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      goto Done;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Look at each protocol interface for a match
 | 
						|
    //
 | 
						|
    DriverImageHandleValid = FALSE;
 | 
						|
    ChildBufferCount = 0;
 | 
						|
 | 
						|
    CoreAcquireProtocolLock ();
 | 
						|
    for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
 | 
						|
      Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
 | 
						|
      for (ProtLink = Prot->OpenList.ForwardLink;
 | 
						|
           ProtLink != &Prot->OpenList;
 | 
						|
           ProtLink = ProtLink->ForwardLink) {
 | 
						|
        OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
 | 
						|
        if (OpenData->AgentHandle == DriverImageHandle) {
 | 
						|
          if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
 | 
						|
            ChildBufferCount++;
 | 
						|
          }
 | 
						|
          if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
 | 
						|
            DriverImageHandleValid = TRUE;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    CoreReleaseProtocolLock ();
 | 
						|
 | 
						|
    if (DriverImageHandleValid) {
 | 
						|
      ChildHandleValid = FALSE;
 | 
						|
      ChildBuffer = NULL;
 | 
						|
      if (ChildBufferCount != 0) {
 | 
						|
        ChildBuffer = AllocatePool (sizeof (EFI_HANDLE) * ChildBufferCount);
 | 
						|
        if (ChildBuffer == NULL) {
 | 
						|
          Status = EFI_OUT_OF_RESOURCES;
 | 
						|
          goto Done;
 | 
						|
        }
 | 
						|
 | 
						|
        ChildBufferCount = 0;
 | 
						|
 | 
						|
        CoreAcquireProtocolLock ();
 | 
						|
        for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
 | 
						|
          Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
 | 
						|
          for (ProtLink = Prot->OpenList.ForwardLink;
 | 
						|
               ProtLink != &Prot->OpenList;
 | 
						|
               ProtLink = ProtLink->ForwardLink) {
 | 
						|
            OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
 | 
						|
            if ((OpenData->AgentHandle == DriverImageHandle) &&
 | 
						|
                ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0)) {
 | 
						|
              Duplicate = FALSE;
 | 
						|
              for (Index = 0; Index < ChildBufferCount; Index++) {
 | 
						|
                if (ChildBuffer[Index] == OpenData->ControllerHandle) {
 | 
						|
                  Duplicate = TRUE;
 | 
						|
                  break;
 | 
						|
                }
 | 
						|
              }
 | 
						|
              if (!Duplicate) {
 | 
						|
                ChildBuffer[ChildBufferCount] = OpenData->ControllerHandle;
 | 
						|
                if (ChildHandle == ChildBuffer[ChildBufferCount]) {
 | 
						|
                  ChildHandleValid = TRUE;
 | 
						|
                }
 | 
						|
                ChildBufferCount++;
 | 
						|
              }
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
        CoreReleaseProtocolLock ();
 | 
						|
      }
 | 
						|
 | 
						|
      if (ChildHandle == NULL || ChildHandleValid) {
 | 
						|
        ChildrenToStop = 0;
 | 
						|
        Status = EFI_SUCCESS;
 | 
						|
        if (ChildBufferCount > 0) {
 | 
						|
          if (ChildHandle != NULL) {
 | 
						|
            ChildrenToStop = 1;
 | 
						|
            Status = DriverBinding->Stop (DriverBinding, ControllerHandle, ChildrenToStop, &ChildHandle);
 | 
						|
          } else {
 | 
						|
            ChildrenToStop = ChildBufferCount;
 | 
						|
            Status = DriverBinding->Stop (DriverBinding, ControllerHandle, ChildrenToStop, ChildBuffer);
 | 
						|
          }
 | 
						|
        }
 | 
						|
        if (!EFI_ERROR (Status) && ((ChildHandle == NULL) || (ChildBufferCount == ChildrenToStop))) {
 | 
						|
          Status = DriverBinding->Stop (DriverBinding, ControllerHandle, 0, NULL);
 | 
						|
        }
 | 
						|
        if (!EFI_ERROR (Status)) {
 | 
						|
          StopCount++;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      if (ChildBuffer != NULL) {
 | 
						|
        CoreFreePool (ChildBuffer);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (StopCount > 0) {
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
  } else {
 | 
						|
    Status = EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
Done:
 | 
						|
 | 
						|
  if (DriverImageHandleBuffer != NULL) {
 | 
						|
    CoreFreePool (DriverImageHandleBuffer);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |