mirror of https://github.com/acidanthera/audk.git
1029 lines
34 KiB
C
1029 lines
34 KiB
C
/*++
|
|
|
|
Copyright (c) 2006, Intel Corporation
|
|
All rights reserved. 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.
|
|
|
|
Module Name:
|
|
|
|
DriverSupport.c
|
|
|
|
Abstract:
|
|
|
|
EFI Driver Support Protocol
|
|
|
|
Revision History
|
|
|
|
--*/
|
|
|
|
#include <DxeMain.h>
|
|
|
|
BOOLEAN mRepairLoadedImage = FALSE;
|
|
|
|
//
|
|
// Driver Support Function Prototypes
|
|
//
|
|
EFI_STATUS
|
|
GetHandleFromDriverBinding (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *DriverBindingNeed,
|
|
OUT EFI_HANDLE *Handle
|
|
);
|
|
|
|
EFI_STATUS
|
|
CoreConnectSingleController (
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_HANDLE *DriverImageHandle OPTIONAL,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
|
|
);
|
|
|
|
//
|
|
// Driver Support Functions
|
|
//
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CoreConnectController (
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_HANDLE *DriverImageHandle OPTIONAL,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL,
|
|
IN BOOLEAN Recursive
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Connects one or more drivers to a controller.
|
|
|
|
Arguments:
|
|
|
|
ControllerHandle - Handle of the controller to be connected.
|
|
|
|
DriverImageHandle - DriverImageHandle A pointer to an ordered list of driver image handles.
|
|
|
|
RemainingDevicePath - RemainingDevicePath A pointer to the device path that specifies a child of the
|
|
controller specified by ControllerHandle.
|
|
|
|
Recursive - Whether the function would be called recursively or not.
|
|
|
|
Returns:
|
|
|
|
Status code.
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
EFI_HANDLE *LoadedImageHandleBuffer;
|
|
UINTN LoadedImageHandleCount;
|
|
LOADED_IMAGE_PRIVATE_DATA *Image;
|
|
EFI_HANDLE DeviceHandle;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
|
|
//
|
|
// 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 = CoreDuplicateDevicePath (RemainingDevicePath);
|
|
}
|
|
|
|
//
|
|
// 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 = CoreAllocateBootServicesPool (ChildHandleCount * sizeof(EFI_HANDLE));
|
|
|
|
//
|
|
// 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);
|
|
}
|
|
|
|
//
|
|
// If a Stop() function has been called one or more time successfully, then attempt to
|
|
// repair the stale DeviceHandle fields of the Loaded Image Protocols
|
|
//
|
|
if (mRepairLoadedImage) {
|
|
//
|
|
// Assume that all Loaded Image Protocols can be repaired
|
|
//
|
|
mRepairLoadedImage = FALSE;
|
|
|
|
//
|
|
// Get list of all Loaded Image Protocol Instances
|
|
//
|
|
Status = CoreLocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiLoadedImageProtocolGuid,
|
|
NULL,
|
|
&LoadedImageHandleCount,
|
|
&LoadedImageHandleBuffer
|
|
);
|
|
if (!EFI_ERROR (Status) && LoadedImageHandleCount != 0) {
|
|
for (Index = 0; Index < LoadedImageHandleCount; Index++) {
|
|
//
|
|
// Retrieve the Loaded Image Protocol
|
|
//
|
|
Image = CoreLoadedImageInfo (LoadedImageHandleBuffer[Index]);
|
|
if (Image != NULL) {
|
|
//
|
|
// Check to see if the DeviceHandle field is a valid handle
|
|
//
|
|
Status = CoreValidateHandle (Image->Info.DeviceHandle);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// The DeviceHandle field is not valid.
|
|
// Attempt to locate a device handle with a device path that matches the one
|
|
// that was used to originally load the image
|
|
//
|
|
DevicePath = Image->DeviceHandleDevicePath;
|
|
if (DevicePath != NULL) {
|
|
Status = CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, &DevicePath, &DeviceHandle);
|
|
if (!EFI_ERROR (Status) && (DeviceHandle != NULL_HANDLE) && IsDevicePathEnd(DevicePath)) {
|
|
//
|
|
// A device handle with a matching device path was found, so update the Loaded Image Protocol
|
|
// with the device handle discovered
|
|
//
|
|
Image->Info.DeviceHandle = DeviceHandle;
|
|
} else {
|
|
//
|
|
// There is still at least one Loaded Image Protocol that requires repair
|
|
//
|
|
mRepairLoadedImage = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CoreFreePool (LoadedImageHandleBuffer);
|
|
}
|
|
}
|
|
|
|
return ReturnStatus;
|
|
}
|
|
|
|
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
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add Driver Binding Protocols from Context Driver Image Handles to sorted
|
|
Driver Binding Protocol list.
|
|
|
|
Arguments:
|
|
|
|
DriverBindingHandle - Handle of the driver binding protocol.
|
|
|
|
NumberOfSortedDriverBindingProtocols - Number Of sorted driver binding protocols
|
|
|
|
SortedDriverBindingProtocols - The sorted protocol list.
|
|
|
|
DriverBindingHandleCount - Driver Binding Handle Count.
|
|
|
|
DriverBindingHandleBuffer - The buffer of driver binding protocol to be modified.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
|
|
UINTN Index;
|
|
|
|
//
|
|
// Make sure the DriverBindingHandle is valid
|
|
//
|
|
Status = CoreValidateHandle (DriverBindingHandle);
|
|
if (EFI_ERROR (Status)) {
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
EFI_STATUS
|
|
CoreConnectSingleController (
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_HANDLE *ContextDriverImageHandles OPTIONAL,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Connects a controller to a driver.
|
|
|
|
Arguments:
|
|
|
|
ControllerHandle - Handle of the controller to be connected.
|
|
ContextDriverImageHandles - DriverImageHandle A pointer to an ordered list of driver image handles.
|
|
RemainingDevicePath - RemainingDevicePath A pointer to the device path that specifies a child
|
|
of the controller specified by ControllerHandle.
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - One or more drivers were connected to ControllerHandle.
|
|
EFI_OUT_OF_RESOURCES - No enough system resources to complete the request.
|
|
EFI_NOT_FOUND - No drivers were connected to ControllerHandle.
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
|
|
UINTN NumberOfSortedDriverBindingProtocols;
|
|
EFI_DRIVER_BINDING_PROTOCOL **SortedDriverBindingProtocols;
|
|
UINT32 HighestVersion;
|
|
UINTN HighestIndex;
|
|
UINTN SortIndex;
|
|
BOOLEAN OneStarted;
|
|
BOOLEAN DriverFound;
|
|
EFI_HANDLE DriverBindingHandle;
|
|
|
|
//
|
|
// DriverBindingHandle is used for performance measurement, initialize it here just in case.
|
|
//
|
|
DriverBindingHandle = NULL;
|
|
//
|
|
// 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 = CoreAllocateBootServicesPool (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
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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
|
|
);
|
|
}
|
|
} 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
|
|
);
|
|
}
|
|
} 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
|
|
);
|
|
}
|
|
|
|
//
|
|
// 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
|
|
//
|
|
if (NumberOfSortedDriverBindingProtocols > 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];
|
|
Status = DriverBinding->Supported(
|
|
DriverBinding,
|
|
ControllerHandle,
|
|
RemainingDevicePath
|
|
);
|
|
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_CODE_BEGIN ();
|
|
GetHandleFromDriverBinding (DriverBinding, &DriverBindingHandle);
|
|
PERF_CODE_END ();
|
|
|
|
PERF_START (DriverBindingHandle, DRIVERBINDING_START_TOK, NULL, 0);
|
|
Status = DriverBinding->Start (
|
|
DriverBinding,
|
|
ControllerHandle,
|
|
RemainingDevicePath
|
|
);
|
|
PERF_END (DriverBindingHandle, DRIVERBINDING_START_TOK, 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;
|
|
}
|
|
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CoreDisconnectController (
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_HANDLE DriverImageHandle OPTIONAL,
|
|
IN EFI_HANDLE ChildHandle OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Disonnects a controller from a driver
|
|
|
|
Arguments:
|
|
|
|
ControllerHandle - ControllerHandle The handle of the controller from which driver(s)
|
|
are to be disconnected.
|
|
DriverImageHandle - DriverImageHandle The driver to disconnect from ControllerHandle.
|
|
ChildHandle - ChildHandle The handle of the child to destroy.
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - One or more drivers were disconnected from the controller.
|
|
EFI_SUCCESS - On entry, no drivers are managing ControllerHandle.
|
|
EFI_SUCCESS - DriverImageHandle is not NULL, and on entry DriverImageHandle is not managing ControllerHandle.
|
|
EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.
|
|
EFI_INVALID_PARAMETER - DriverImageHandle is not NULL, and it is not a valid EFI_HANDLE.
|
|
EFI_INVALID_PARAMETER - ChildHandle is not NULL, and it is not a valid EFI_HANDLE.
|
|
EFI_OUT_OF_RESOURCES - There are not enough resources available to disconnect any drivers from ControllerHandle.
|
|
EFI_DEVICE_ERROR - The controller could not be disconnected because of a device error.
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
EFI_HANDLE *LoadedImageHandleBuffer;
|
|
UINTN LoadedImageHandleCount;
|
|
LOADED_IMAGE_PRIVATE_DATA *Image;
|
|
|
|
//
|
|
// 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 = CoreAllocateBootServicesPool (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)) {
|
|
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 = CoreAllocateBootServicesPool (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) {
|
|
//
|
|
// If the Loaded Image Protocols do not already need to be repaired, then
|
|
// check the status of the DeviceHandle field of all Loaded Image Protocols
|
|
// to determine if any of them now need repair because a sucessful Stop()
|
|
// may have destroyed the DeviceHandle value in the Loaded Image Protocol
|
|
//
|
|
if (!mRepairLoadedImage) {
|
|
//
|
|
// Get list of all Loaded Image Protocol Instances
|
|
//
|
|
Status = CoreLocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiLoadedImageProtocolGuid,
|
|
NULL,
|
|
&LoadedImageHandleCount,
|
|
&LoadedImageHandleBuffer
|
|
);
|
|
if (!EFI_ERROR (Status) && LoadedImageHandleCount != 0) {
|
|
for (Index = 0; Index < LoadedImageHandleCount; Index++) {
|
|
//
|
|
// Retrieve the Loaded Image Protocol
|
|
//
|
|
Image = CoreLoadedImageInfo (LoadedImageHandleBuffer[Index]);
|
|
if (Image != NULL) {
|
|
//
|
|
// Check to see if the DeviceHandle field is a valid handle
|
|
//
|
|
Status = CoreValidateHandle (Image->Info.DeviceHandle);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// The DeviceHandle field is not longer a valid handle. This means
|
|
// that future calls to ConnectController() need to attemp to repair
|
|
// the Loaded Image Protocols with invalid DeviceHandle fields. Set
|
|
// the flag used by ConnectController().
|
|
//
|
|
mRepairLoadedImage = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
CoreFreePool (LoadedImageHandleBuffer);
|
|
}
|
|
}
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
Status = EFI_NOT_FOUND;
|
|
}
|
|
|
|
Done:
|
|
|
|
if (DriverImageHandleBuffer != NULL) {
|
|
CoreFreePool (DriverImageHandleBuffer);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
GetHandleFromDriverBinding (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *DriverBindingNeed,
|
|
OUT EFI_HANDLE *Handle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Locate the driver binding handle which a specified driver binding protocol installed on.
|
|
|
|
Arguments:
|
|
|
|
DriverBindingNeed - The specified driver binding protocol.
|
|
|
|
Handle - The driver binding handle which the protocol installed on.
|
|
|
|
|
|
Returns:
|
|
|
|
EFI_NOT_FOUND - Could not find the handle.
|
|
|
|
EFI_SUCCESS - Successfully find the associated driver binding handle.
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status ;
|
|
EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
|
|
UINTN DriverBindingHandleCount;
|
|
EFI_HANDLE *DriverBindingHandleBuffer;
|
|
UINTN Index;
|
|
|
|
DriverBindingHandleCount = 0;
|
|
DriverBindingHandleBuffer = NULL;
|
|
*Handle = NULL_HANDLE;
|
|
Status = CoreLocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiDriverBindingProtocolGuid,
|
|
NULL,
|
|
&DriverBindingHandleCount,
|
|
&DriverBindingHandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status) || DriverBindingHandleCount == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
for (Index = 0 ; Index < DriverBindingHandleCount; Index++ ) {
|
|
Status = CoreOpenProtocol(
|
|
DriverBindingHandleBuffer[Index],
|
|
&gEfiDriverBindingProtocolGuid,
|
|
(VOID **)&DriverBinding,
|
|
gDxeCoreImageHandle,
|
|
NULL,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
|
|
if (!EFI_ERROR (Status) && DriverBinding != NULL) {
|
|
|
|
if ( DriverBinding == DriverBindingNeed ) {
|
|
*Handle = DriverBindingHandleBuffer[Index];
|
|
CoreFreePool (DriverBindingHandleBuffer);
|
|
return EFI_SUCCESS ;
|
|
}
|
|
}
|
|
}
|
|
|
|
CoreFreePool (DriverBindingHandleBuffer);
|
|
return EFI_NOT_FOUND ;
|
|
}
|
|
|