/**
* @file MnpDriver.c
*
* @brief MNP DXE Driver - Driver Binding and Service Binding Implementation
*
* Implements the EFI driver binding protocol (Supported, Start, Stop) and
* the EFI service binding protocol (CreateChild, DestroyChild) for the
* Managed Network Protocol.
*
* Architecture:
* MNP_DEVICE_DATA (per-NIC)
* -> MNP_SERVICE_DATA (per-VLAN, linked via MnpDeviceData->ServiceList)
* -> MNP_INSTANCE_DATA (per-opened-protocol, linked via Service->InstanceList)
*
* Source: AmiNetworkPkg/UefiNetworkStack/Common/MnpDxe/MnpDriver.c
*/
#include "MnpDxe.h"
//
// GUID definitions (extern references to globals in the data section)
//
EFI_GUID gMnpDriverBindingGuid = EFI_DRIVER_BINDING_PROTOCOL_GUID;
EFI_GUID gMnpServiceBindingGuid = EFI_MANAGED_NETWORK_SERVICE_BINDING_PROTOCOL_GUID;
EFI_GUID gMnpProtocolGuid = EFI_MANAGED_NETWORK_PROTOCOL_GUID;
EFI_GUID gMnpSnpProtocolGuid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
EFI_GUID gMnpDevicePathGuid = EFI_DEVICE_PATH_PROTOCOL_GUID;
EFI_GUID gMnpVlanConfigGuid = EFI_VLAN_CONFIG_PROTOCOL_GUID;
EFI_GUID gMnpComponentNameGuid = EFI_COMPONENT_NAME2_PROTOCOL_GUID;
//
// External globals
//
extern EFI_BOOT_SERVICES *gBS;
extern EFI_HANDLE gImageHandle;
//
// Forward declarations
//
EFI_STATUS
EFIAPI
MnpDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
);
EFI_STATUS
EFIAPI
MnpDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
);
EFI_STATUS
EFIAPI
MnpDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
);
EFI_STATUS
EFIAPI
MnpServiceBindingCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE *ChildHandle
);
EFI_STATUS
EFIAPI
MnpServiceBindingDestroyChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE ChildHandle
);
//
// Driver Binding Protocol instance
//
EFI_DRIVER_BINDING_PROTOCOL gMnpDriverBinding = {
MnpDriverBindingSupported,
MnpDriverBindingStart,
MnpDriverBindingStop,
0x0A, /* Version = 10 */
NULL, /* ImageHandle (filled at entry) */
NULL /* DriverBindingHandle (filled later) */
};
/* ====================================================================== */
/* MnpDriverBindingSupported */
/* ====================================================================== */
/**
* Test whether the driver supports the controller.
*
* Opens the SNP protocol on ControllerHandle; if it succeeds and the
* controller does NOT already have a DevicePath child (which would indicate
* a child handle rather than a NIC handle), returns EFI_SUCCESS.
*
* @param[in] This Driver binding protocol.
* @param[in] ControllerHandle Handle to test.
* @param[in] RemainingDevicePath Optional device path.
*
* @retval EFI_SUCCESS Controller is supported.
* @retval EFI_UNSUPPORTED Controller is not supported.
*/
EFI_STATUS
EFIAPI
MnpDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
EFI_STATUS Status;
Status = gBS->OpenProtocol (
ControllerHandle,
&gMnpSnpProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (EFI_ERROR (Status)) {
return Status;
}
gBS->CloseProtocol (
ControllerHandle,
&gMnpSnpProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
//
// If the handle has a DevicePath protocol that is a child handle
// (i.e. not the root), return UNSUPPORTED.
//
{
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
UINTN DevPathSize;
DevicePath = DevicePathFromHandle (ControllerHandle);
if (DevicePath != NULL && !IsDevicePathEnd (DevicePath)) {
//
// This is a child handle; do not bind directly.
//
DEBUG ((DEBUG_ERROR, "Returning EFI_UNSUPPORTED\n"));
return EFI_UNSUPPORTED;
}
}
return EFI_SUCCESS;
}
/* ====================================================================== */
/* MnpDriverBindingStart */
/* ====================================================================== */
/**
* Start the MNP driver on a controller handle.
*
* Allocates and initializes a MNP_DEVICE_DATA structure, opens the SNP
* protocol, creates service data instances (VLAN and non-VLAN), and
* installs the driver binding protocol.
*
* @param[in] This Driver binding protocol.
* @param[in] ControllerHandle Handle to start.
* @param[in] RemainingDevicePath Optional device path.
*
* @retval EFI_SUCCESS Driver started.
* @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
* @retval Others Error from sub-operations.
*/
EFI_STATUS
EFIAPI
MnpDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
MNP_DEVICE_DATA *MnpDeviceData;
EFI_STATUS Status;
UINTN NumberOfVlan;
UINT16 *VlanVariable;
UINTN Index;
//
// Allocate MNP_DEVICE_DATA (size includes free NET_BUF queue).
//
MnpDeviceData = AllocateZeroPool (sizeof (MNP_DEVICE_DATA));
if (MnpDeviceData == NULL) {
DEBUG ((DEBUG_ERROR,
"MnpDriverBindingStart(): Failed to allocate the Mnp Device Data.\n"));
return EFI_OUT_OF_RESOURCES;
}
Status = MnpInitializeDeviceData (
MnpDeviceData,
This->DriverBindingHandle,
ControllerHandle
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR,
"MnpDriverBindingStart: MnpInitializeDeviceData failed, %r.\n",
Status));
goto ErrorFreeDeviceData;
}
//
// Open the driver binding protocol on the controller handle.
//
Status = gBS->OpenProtocol (
&ControllerHandle,
&gMnpDriverBindingGuid,
&MnpDeviceData->DriverBindingHandle,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (Status == EFI_ALREADY_STARTED) {
//
// Protocol already opened; check VLAN config.
//
gBS->CloseProtocol (
&ControllerHandle,
&gMnpDriverBindingGuid,
This->DriverBindingHandle,
ControllerHandle
);
ZeroMem (&MnpDeviceData->DriverBindingHandle,
sizeof (MnpDeviceData->DriverBindingHandle));
//
// Open the device path protocol for VLAN.
//
Status = gBS->OpenProtocol (
&ControllerHandle,
&gMnpDevicePathGuid,
&DevicePathInterface,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
goto DestroyServices;
}
//
// Read the VLAN configuration variable.
//
NumberOfVlan = 0;
VlanVariable = NULL;
Status = MnpReadVlanConfiguration (
MnpDeviceData,
&NumberOfVlan,
&VlanVariable
);
if (!EFI_ERROR (Status)) {
MnpDeviceData->NumberOfVlan = NumberOfVlan;
if (NumberOfVlan > 0) {
//
// Create one service data per VLAN.
//
for (Index = 0; Index < NumberOfVlan; Index++) {
if (!MnpCreateServiceData (
MnpDeviceData,
VlanVariable[Index] & 0xFFF,
(UINT8)((VlanVariable[Index] >> 13) & 7)
)) {
Status = EFI_OUT_OF_RESOURCES;
break;
}
}
} else {
MnpDeviceData->NumberOfVlan = 0;
Status = MnpCreateServiceData (MnpDeviceData, 0, 0)
? EFI_SUCCESS
: EFI_OUT_OF_RESOURCES;
}
} else {
//
// No VLAN variable; create a default service data.
//
MnpDeviceData->NumberOfVlan = 0;
Status = MnpCreateServiceData (MnpDeviceData, 0, 0)
? EFI_SUCCESS
: EFI_OUT_OF_RESOURCES;
}
if (VlanVariable != NULL) {
FreePool (VlanVariable);
}
} else if (Status == EFI_SUCCESS) {
//
// First open; create a default service.
//
MnpDeviceData->NumberOfVlan = 0;
Status = MnpCreateServiceData (MnpDeviceData, 0, 0)
? EFI_SUCCESS
: EFI_OUT_OF_RESOURCES;
}
if (!EFI_ERROR (Status)) {
if (MnpDeviceData->NumberOfVlan > 0) {
Status = EFI_SUCCESS;
}
return Status;
}
DestroyServices:
//
// Clean up all service data entries.
//
while (!IsListEmpty (&MnpDeviceData->ServiceList)) {
LIST_ENTRY *Entry;
MNP_SERVICE_DATA *Service;
Entry = GetFirstNode (&MnpDeviceData->ServiceList);
if (((MNP_SERVICE_DATA *)Entry)->Signature == MNP_SERVICE_DATA_SIGNATURE) {
Service = (MNP_SERVICE_DATA *)Entry;
} else {
CR_CHECK_FAIL (Entry);
Service = (MNP_SERVICE_DATA *)Entry;
}
MnpDestroyServiceData (Service);
}
if (MnpDeviceData->DriverBindingHandle != 0) {
gBS->CloseProtocol (
ControllerHandle,
&gMnpDriverBindingGuid,
MnpDeviceData->DriverBindingHandle,
0
);
}
MnpReleaseDeviceData (MnpDeviceData, This->DriverBindingHandle);
ErrorFreeDeviceData:
FreePool (MnpDeviceData);
return Status;
}
/* ====================================================================== */
/* MnpDriverBindingStop */
/* ====================================================================== */
/**
* Stop the MNP driver on a controller handle.
*
* @param[in] This Driver binding protocol.
* @param[in] ControllerHandle Handle to stop.
* @param[in] NumberOfChildren Number of child handles.
* @param[in] ChildHandleBuffer Array of child handles.
*
* @retval EFI_SUCCESS Driver stopped.
* @retval EFI_DEVICE_ERROR Failed to stop.
*/
EFI_STATUS
EFIAPI
MnpDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
)
{
MNP_DEVICE_DATA *MnpDeviceData;
MNP_SERVICE_DATA *Service;
EFI_STATUS Status;
LIST_ENTRY *Entry;
EFI_HANDLE SnpChildHandle;
UINTN DevicePathSize;
BOOLEAN ByDevicePath;
//
// Locate the MNP device data.
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gMnpDevicePathGuid,
(VOID **)&DevicePathInterface,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (!EFI_ERROR (Status)) {
//
// Found via device path -> get MNP_SERVICE_DATA from controller
// handle (child handle). Back-calculate to MNP_DEVICE_DATA.
//
Service = MNP_SERVICE_DATA_FROM_DEVICE_PATH (DevicePathInterface);
MnpDeviceData = Service->MnpDeviceData;
} else {
Status = gBS->OpenProtocol (
ControllerHandle,
&gMnpDriverBindingGuid,
(VOID **)&MnpDeviceData,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR,
"MnpDriverBindingStop: try to stop unknown Controller.\n"));
return EFI_DEVICE_ERROR;
}
//
// Verify signature.
//
if (MnpDeviceData->Signature != MNP_DEVICE_DATA_SIGNATURE) {
MnpDeviceData = (MNP_DEVICE_DATA *)((UINTN)MnpDeviceData -
OFFSET_OF(MNP_DEVICE_DATA,
DriverBindingHandle));
}
}
if (NumberOfChildren > 0) {
//
// Destroy specific children.
//
Status = NetMapIterate (
&MnpDeviceData->ServiceList,
(NET_MAP_ITEM_CALLBACK)MnpDestroyChildByHandle,
ChildHandleBuffer
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
return EFI_SUCCESS;
}
//
// Destroy all services and release the device data.
//
while (!IsListEmpty (&MnpDeviceData->ServiceList)) {
Entry = GetFirstNode (&MnpDeviceData->ServiceList);
Service = MNP_SERVICE_DATA_FROM_LINK (Entry);
MnpDestroyServiceData (Service);
}
if (MnpDeviceData->DriverBindingHandle != 0) {
gBS->CloseProtocol (
ControllerHandle,
&gMnpDriverBindingGuid,
MnpDeviceData->DriverBindingHandle,
ControllerHandle
);
}
MnpReleaseDeviceData (MnpDeviceData, This->DriverBindingHandle);
FreePool (MnpDeviceData);
if (gComponentNameTable != NULL) {
FreeUnicodeStringTable (gComponentNameTable);
gComponentNameTable = NULL;
}
return EFI_SUCCESS;
}
/* ====================================================================== */
/* MnpServiceBindingCreateChild */
/* ====================================================================== */
/**
* Create a child MNP instance on the service.
*
* Allocates and initializes an MNP_INSTANCE_DATA, installs the MNP protocol
* on a new child handle, and adds it to the service's instance list.
*
* @param[in] This Service binding protocol.
* @param[in,out] ChildHandle On input, optional handle; on output, new child.
*
* @retval EFI_SUCCESS Child created.
* @retval EFI_INVALID_PARAMETER Invalid parameter.
* @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
*/
EFI_STATUS
EFIAPI
MnpServiceBindingCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN OUT EFI_HANDLE *ChildHandle
)
{
MNP_SERVICE_DATA *Service;
MNP_INSTANCE_DATA *Instance;
EFI_STATUS Status;
EFI_TPL OldTpl;
if (This == NULL || ChildHandle == NULL) {
return EFI_INVALID_PARAMETER;
}
Service = MNP_SERVICE_DATA_FROM_THIS (This);
Instance = AllocateZeroPool (sizeof (MNP_INSTANCE_DATA));
if (Instance == NULL) {
DEBUG ((DEBUG_ERROR,
"MnpServiceBindingCreateChild: Faild to allocate memory for "
"the new instance.\n"));
return EFI_OUT_OF_RESOURCES;
}
MnpInitializeInstanceData (Service, Instance);
//
// Install the MNP protocol on a new child handle.
//
Status = gBS->InstallMultipleProtocolInterfaces (
ChildHandle,
&gMnpProtocolGuid,
&Instance->Protocol,
NULL
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR,
"MnpServiceBindingCreateChild: Failed to install the "
"MNP protocol, %r.\n", Status));
goto ErrorFreeInstance;
}
Instance->Handle = *ChildHandle;
//
// Open the device path protocol from the service handle to the new child.
//
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
Status = gBS->OpenProtocol (
Service->ControllerHandle,
&gMnpDevicePathGuid,
&DevicePathInterface,
gImageHandle,
*ChildHandle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
if (EFI_ERROR (Status)) {
gBS->RestoreTPL (OldTpl);
goto ErrorUninstallProtocol;
}
InsertTailList (&Service->InstanceList, &Instance->Link);
Service->InstanceCount++;
gBS->RestoreTPL (OldTpl);
return EFI_SUCCESS;
ErrorUninstallProtocol:
gBS->UninstallMultipleProtocolInterfaces (
*ChildHandle,
&gMnpProtocolGuid,
&Instance->Protocol,
NULL
);
ErrorFreeInstance:
FreePool (Instance);
return Status;
}
/* ====================================================================== */
/* MnpServiceBindingDestroyChild */
/* ====================================================================== */
/**
* Destroy a child MNP instance.
*
* @param[in] This Service binding protocol.
* @param[in] ChildHandle Handle of the child to destroy.
*
* @retval EFI_SUCCESS Child destroyed.
* @retval EFI_INVALID_PARAMETER Invalid parameter.
* @retval EFI_UNSUPPORTED Protocol not found on child.
*/
EFI_STATUS
EFIAPI
MnpServiceBindingDestroyChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE ChildHandle
)
{
MNP_SERVICE_DATA *Service;
MNP_INSTANCE_DATA *Instance;
EFI_STATUS Status;
EFI_TPL OldTpl;
VOID *ProtocolInterface;
if (This == NULL || ChildHandle == NULL) {
return EFI_INVALID_PARAMETER;
}
Service = MNP_SERVICE_DATA_FROM_THIS (This);
//
// Locate the MNP protocol on the child handle.
//
Status = gBS->OpenProtocol (
ChildHandle,
&gMnpProtocolGuid,
&ProtocolInterface,
gImageHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
Instance = MNP_INSTANCE_DATA_FROM_THIS ((EFI_MANAGED_NETWORK_PROTOCOL *)ProtocolInterface);
if (Instance->IsDestroyed) {
return EFI_SUCCESS;
}
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
Instance->IsDestroyed = TRUE;
//
// Close the device path protocol opened for this child.
//
gBS->CloseProtocol (
Service->ControllerHandle,
&gMnpDevicePathGuid,
gImageHandle,
ChildHandle
);
//
// Uninstall the MNP protocol.
//
Status = gBS->UninstallMultipleProtocolInterfaces (
ChildHandle,
&gMnpProtocolGuid,
&Instance->Protocol,
NULL
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR,
"MnpServiceBindingDestroyChild: Failed to uninstall the "
"ManagedNetwork protocol, %r.\n", Status));
Instance->IsDestroyed = FALSE;
gBS->RestoreTPL (OldTpl);
return Status;
}
//
// Clean up instance state.
//
MnpCleanInstance (Instance);
NetMapClean (&Instance->RcvMap);
//
// Remove from the service's instance list.
//
RemoveEntryList (&Instance->Link);
Service->InstanceCount--;
gBS->RestoreTPL (OldTpl);
FreePool (Instance);
return EFI_SUCCESS;
}
/* ====================================================================== */
/* MnpComponentNameGetDriverName */
/* ====================================================================== */
/**
* Retrieves the driver name.
*
* @param[in] This Component name protocol.
* @param[in] Language Language code.
* @param[out] DriverName Driver name string.
*
* @retval EFI_SUCCESS Name returned.
* @retval EFI_UNSUPPORTED Language not supported.
*/
EFI_STATUS
EFIAPI
MnpComponentNameGetDriverName (
IN EFI_COMPONENT_NAME2_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
{
return LookupUnicodeString2 (
Language,
This->SupportedLanguages,
&gMnpDriverNameTable,
DriverName,
(This == &gMnpComponentName2)
);
}
/* ====================================================================== */
/* MnpComponentNameGetControllerName */
/* ====================================================================== */
/**
* Retrieves the controller name.
*
* Queries the SNP and MNP protocols on the controller and formats a
* descriptive name string.
*
* @param[in] This Component name protocol.
* @param[in] Controller Controller handle.
* @param[in] ChildHandle Child handle (MNP instance).
* @param[in] Language Language code.
* @param[out] ControllerName Controller name string.
*
* @retval EFI_SUCCESS Name returned.
* @retval EFI_UNSUPPORTED Controller not supported.
*/
EFI_STATUS
EFIAPI
MnpComponentNameGetControllerName (
IN EFI_COMPONENT_NAME2_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK *Snp;
MNP_INSTANCE_DATA *Instance;
MNP_SERVICE_DATA *Service;
EFI_HANDLE SnpHandle;
CHAR16 NameString[80];
UINTN Offset;
UINTN Index;
if (ChildHandle == NULL) {
return EFI_UNSUPPORTED;
}
//
// Locate the SNP protocol to verify the controller.
//
Status = gBS->OpenProtocol (
Controller,
&gMnpSnpProtocolGuid,
(VOID **)&Snp,
gImageHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (Status == EFI_SUCCESS) {
gBS->CloseProtocol (
Controller,
&gMnpSnpProtocolGuid,
gImageHandle,
Controller
);
return EFI_UNSUPPORTED;
}
if (Status != EFI_NOT_FOUND) {
return EFI_UNSUPPORTED;
}
//
// Locate the device path protocol on the controller.
//
{
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
UINTN DevicePathSize;
Status = gBS->OpenProtocol (
Controller,
&gMnpDevicePathGuid,
(VOID **)&DevicePath,
gImageHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
Status = FindControllerHandleForDevicePath (
Controller,
DevicePath,
&SnpHandle,
&DevicePathSize
);
if (EFI_ERROR (Status)) {
return Status;
}
}
//
// Try to get the MNP instance to query protocol type and VLAN.
//
Status = gBS->OpenProtocol (
ChildHandle,
&gMnpProtocolGuid,
(VOID **)&Instance,
0,
0,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = MnpControllerName (Instance);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Free the old table and rebuild.
//
if (gComponentNameTable != NULL) {
FreeUnicodeStringTable (gComponentNameTable);
gComponentNameTable = NULL;
}
return AddUnicodeString2 (
Language,
&gMnpDriverNameTable,
ControllerName,
NameString,
(This == &gMnpComponentName2)
);
}
/* ====================================================================== */
/* Driver Unload */
/* ====================================================================== */
/**
* Unload the MNP driver.
*
* Iterates all handles with the service binding protocol installed and
* uninstalls them if the driver binding handle matches ImageHandle.
*
* @param[in] ImageHandle The image handle of the driver.
*
* @retval EFI_SUCCESS Driver unloaded.
* @retval Others Error from LocateHandleBuffer.
*/
EFI_STATUS
EFIAPI
MnpUnload (
IN EFI_HANDLE ImageHandle
)
{
EFI_STATUS Status;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
UINTN Index;
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gMnpServiceBindingGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
return Status;
}
for (Index = 0; Index < HandleCount; Index++) {
EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
Status = gBS->OpenProtocol (
HandleBuffer[Index],
&gMnpServiceBindingGuid,
(VOID **)&ServiceBinding,
gImageHandle,
HandleBuffer[Index],
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (!EFI_ERROR (Status) &&
ServiceBinding->ImageHandle == ImageHandle) {
//
// Close all child protocol opens.
//
UINTN SubIndex;
for (SubIndex = 0; SubIndex < HandleCount; SubIndex++) {
gBS->CloseProtocol (
HandleBuffer[SubIndex],
ServiceBinding->ProtocolGuid,
0,
ServiceBinding->ImageHandle
);
}
//
// Uninstall the service binding protocol.
//
gBS->UninstallMultipleProtocolInterfaces (
HandleBuffer[Index],
&gMnpServiceBindingGuid,
ServiceBinding,
NULL
);
//
// Uninstall component name protocol if present.
//
{
EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;
Status = gBS->OpenProtocol (
HandleBuffer[Index],
&gMnpComponentNameGuid,
(VOID **)&ComponentName2,
gImageHandle,
HandleBuffer[Index],
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (!EFI_ERROR (Status)) {
gBS->UninstallMultipleProtocolInterfaces (
HandleBuffer[Index],
&gMnpComponentNameGuid,
ComponentName2,
NULL
);
}
}
}
}
if (HandleBuffer != NULL) {
FreePool (HandleBuffer);
}
return EFI_SUCCESS;
}