| /** @file | |
| Support functions to connect/disconnect UEFI Driver model Protocol | |
| Copyright (c) 2006 - 2014, 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 The handle of the controller to which driver(s) are to be connected. | |
| @param DriverImageHandle A pointer to an ordered list handles that support the | |
| EFI_DRIVER_BINDING_PROTOCOL. | |
| @param RemainingDevicePath A pointer to the device path that specifies a child of the | |
| controller specified by ControllerHandle. | |
| @param Recursive If TRUE, then ConnectController() is called recursively | |
| until the entire tree of controllers below the controller specified | |
| by ControllerHandle have been created. If FALSE, then | |
| the tree of controllers is only expanded one level. | |
| @retval EFI_SUCCESS 1) One or more drivers were connected to ControllerHandle. | |
| 2) No drivers were connected to ControllerHandle, but | |
| RemainingDevicePath is not NULL, and it is an End Device | |
| Path Node. | |
| @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. | |
| @retval EFI_NOT_FOUND 1) There are no EFI_DRIVER_BINDING_PROTOCOL instances | |
| present in the system. | |
| 2) No drivers were connected to ControllerHandle. | |
| @retval EFI_SECURITY_VIOLATION | |
| The user has no permission to start UEFI device drivers on the device path | |
| associated with the ControllerHandle or specified by the RemainingDevicePath. | |
| **/ | |
| 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; | |
| UINTN HandleFilePathSize; | |
| UINTN RemainingDevicePathSize; | |
| EFI_DEVICE_PATH_PROTOCOL *HandleFilePath; | |
| EFI_DEVICE_PATH_PROTOCOL *FilePath; | |
| EFI_DEVICE_PATH_PROTOCOL *TempFilePath; | |
| // | |
| // Make sure ControllerHandle is valid | |
| // | |
| Status = CoreValidateHandle (ControllerHandle); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| if (gSecurity2 != NULL) { | |
| // | |
| // Check whether the user has permission to start UEFI device drivers. | |
| // | |
| Status = CoreHandleProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath); | |
| if (!EFI_ERROR (Status)) { | |
| ASSERT (HandleFilePath != NULL); | |
| FilePath = HandleFilePath; | |
| TempFilePath = NULL; | |
| if (RemainingDevicePath != NULL && !Recursive) { | |
| HandleFilePathSize = GetDevicePathSize (HandleFilePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); | |
| RemainingDevicePathSize = GetDevicePathSize (RemainingDevicePath); | |
| TempFilePath = AllocateZeroPool (HandleFilePathSize + RemainingDevicePathSize); | |
| ASSERT (TempFilePath != NULL); | |
| CopyMem (TempFilePath, HandleFilePath, HandleFilePathSize); | |
| CopyMem ((UINT8 *) TempFilePath + HandleFilePathSize, RemainingDevicePath, RemainingDevicePathSize); | |
| FilePath = TempFilePath; | |
| } | |
| Status = gSecurity2->FileAuthentication ( | |
| gSecurity2, | |
| FilePath, | |
| NULL, | |
| 0, | |
| FALSE | |
| ); | |
| if (TempFilePath != NULL) { | |
| FreePool (TempFilePath); | |
| } | |
| 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; | |
| EFI_DRIVER_FAMILY_OVERRIDE_PROTOCOL *DriverFamilyOverride; | |
| UINTN NumberOfSortedDriverBindingProtocols; | |
| EFI_DRIVER_BINDING_PROTOCOL **SortedDriverBindingProtocols; | |
| UINT32 DriverFamilyOverrideVersion; | |
| UINT32 HighestVersion; | |
| UINTN HighestIndex; | |
| UINTN SortIndex; | |
| BOOLEAN OneStarted; | |
| BOOLEAN DriverFound; | |
| // | |
| // Initialize local variables | |
| // | |
| DriverBindingHandleCount = 0; | |
| DriverBindingHandleBuffer = NULL; | |
| NumberOfSortedDriverBindingProtocols = 0; | |
| SortedDriverBindingProtocols = NULL; | |
| PlatformDriverOverride = NULL; | |
| NewDriverBindingHandleBuffer = 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)); | |
| } | |
| // | |
| // Add the Driver Family Override Protocol drivers for ControllerHandle | |
| // | |
| while (TRUE) { | |
| HighestIndex = DriverBindingHandleCount; | |
| HighestVersion = 0; | |
| for (Index = 0; Index < DriverBindingHandleCount; Index++) { | |
| Status = CoreHandleProtocol ( | |
| DriverBindingHandleBuffer[Index], | |
| &gEfiDriverFamilyOverrideProtocolGuid, | |
| (VOID **) &DriverFamilyOverride | |
| ); | |
| if (!EFI_ERROR (Status) && (DriverFamilyOverride != NULL)) { | |
| DriverFamilyOverrideVersion = DriverFamilyOverride->GetVersion (DriverFamilyOverride); | |
| if ((HighestIndex == DriverBindingHandleCount) || (DriverFamilyOverrideVersion > HighestVersion)) { | |
| HighestVersion = DriverFamilyOverrideVersion; | |
| HighestIndex = Index; | |
| } | |
| } | |
| } | |
| if (HighestIndex == DriverBindingHandleCount) { | |
| break; | |
| } | |
| AddSortedDriverBindingProtocol ( | |
| DriverBindingHandleBuffer[HighestIndex], | |
| &NumberOfSortedDriverBindingProtocols, | |
| SortedDriverBindingProtocols, | |
| DriverBindingHandleCount, | |
| DriverBindingHandleBuffer, | |
| FALSE | |
| ); | |
| } | |
| // | |
| // 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 NULL. | |
| @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; | |
| } |