/** @file | |
Top level C file for debugport driver. Contains initialization function. | |
This driver layers on top of SerialIo. | |
ALL CODE IN THE SERIALIO STACK MUST BE RE-ENTRANT AND CALLABLE FROM | |
INTERRUPT CONTEXT | |
Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "DebugPort.h" | |
// | |
// Globals | |
// | |
EFI_DRIVER_BINDING_PROTOCOL gDebugPortDriverBinding = { | |
DebugPortSupported, | |
DebugPortStart, | |
DebugPortStop, | |
DEBUGPORT_DRIVER_VERSION, | |
NULL, | |
NULL | |
}; | |
DEBUGPORT_DEVICE mDebugPortDevice = { | |
DEBUGPORT_DEVICE_SIGNATURE, | |
(EFI_HANDLE)0, | |
(EFI_HANDLE)0, | |
(EFI_DEVICE_PATH_PROTOCOL *)NULL, | |
{ | |
DebugPortReset, | |
DebugPortWrite, | |
DebugPortRead, | |
DebugPortPoll | |
}, | |
(EFI_HANDLE)0, | |
(EFI_SERIAL_IO_PROTOCOL *)NULL, | |
DEBUGPORT_UART_DEFAULT_BAUDRATE, | |
DEBUGPORT_UART_DEFAULT_FIFO_DEPTH, | |
DEBUGPORT_UART_DEFAULT_TIMEOUT, | |
(EFI_PARITY_TYPE)DEBUGPORT_UART_DEFAULT_PARITY, | |
DEBUGPORT_UART_DEFAULT_DATA_BITS, | |
(EFI_STOP_BITS_TYPE)DEBUGPORT_UART_DEFAULT_STOP_BITS | |
}; | |
/** | |
Local worker function to obtain device path information from DebugPort variable. | |
Records requested settings in DebugPort device structure. | |
**/ | |
EFI_DEVICE_PATH_PROTOCOL * | |
GetDebugPortVariable ( | |
VOID | |
) | |
{ | |
UINTN DataSize; | |
EFI_DEVICE_PATH_PROTOCOL *DebugPortVariable; | |
EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
GetVariable2 (EFI_DEBUGPORT_VARIABLE_NAME, &gEfiDebugPortVariableGuid, (VOID **)&DebugPortVariable, &DataSize); | |
if (DebugPortVariable == NULL) { | |
return NULL; | |
} | |
DevicePath = DebugPortVariable; | |
while (!IsDevicePathEnd (DevicePath) && !IS_UART_DEVICEPATH (DevicePath)) { | |
DevicePath = NextDevicePathNode (DevicePath); | |
} | |
if (IsDevicePathEnd (DevicePath)) { | |
FreePool (DebugPortVariable); | |
return NULL; | |
} else { | |
CopyMem ( | |
&mDebugPortDevice.BaudRate, | |
&((UART_DEVICE_PATH *)DevicePath)->BaudRate, | |
sizeof (((UART_DEVICE_PATH *)DevicePath)->BaudRate) | |
); | |
mDebugPortDevice.ReceiveFifoDepth = DEBUGPORT_UART_DEFAULT_FIFO_DEPTH; | |
mDebugPortDevice.Timeout = DEBUGPORT_UART_DEFAULT_TIMEOUT; | |
CopyMem ( | |
&mDebugPortDevice.Parity, | |
&((UART_DEVICE_PATH *)DevicePath)->Parity, | |
sizeof (((UART_DEVICE_PATH *)DevicePath)->Parity) | |
); | |
CopyMem ( | |
&mDebugPortDevice.DataBits, | |
&((UART_DEVICE_PATH *)DevicePath)->DataBits, | |
sizeof (((UART_DEVICE_PATH *)DevicePath)->DataBits) | |
); | |
CopyMem ( | |
&mDebugPortDevice.StopBits, | |
&((UART_DEVICE_PATH *)DevicePath)->StopBits, | |
sizeof (((UART_DEVICE_PATH *)DevicePath)->StopBits) | |
); | |
return DebugPortVariable; | |
} | |
} | |
/** | |
Debug Port Driver entry point. | |
Reads DebugPort variable to determine what device and settings to use as the | |
debug port. Binds exclusively to SerialIo. Reverts to defaults if no variable | |
is found. | |
@param[in] ImageHandle The firmware allocated handle for the EFI image. | |
@param[in] SystemTable A pointer to the EFI System Table. | |
@retval EFI_SUCCESS The entry point is executed successfully. | |
@retval EFI_OUT_OF_RESOURCES Fails to allocate memory for device. | |
@retval other Some error occurs when executing this entry point. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
InitializeDebugPortDriver ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
EFI_STATUS Status; | |
// | |
// Install driver model protocol(s). | |
// | |
Status = EfiLibInstallDriverBindingComponentName2 ( | |
ImageHandle, | |
SystemTable, | |
&gDebugPortDriverBinding, | |
ImageHandle, | |
&gDebugPortComponentName, | |
&gDebugPortComponentName2 | |
); | |
ASSERT_EFI_ERROR (Status); | |
return Status; | |
} | |
/** | |
Checks to see if there's not already a DebugPort interface somewhere. | |
If there's a DEBUGPORT variable, the device path must match exactly. If there's | |
no DEBUGPORT variable, then device path is not checked and does not matter. | |
Checks to see that there's a serial io interface on the controller handle | |
that can be bound BY_DRIVER | EXCLUSIVE. | |
If all these tests succeed, then we return EFI_SUCCESS, else, EFI_UNSUPPORTED | |
or other error returned by OpenProtocol. | |
@param This Protocol instance pointer. | |
@param ControllerHandle Handle of device to test. | |
@param RemainingDevicePath Optional parameter use to pick a specific child | |
device to start. | |
@retval EFI_SUCCESS This driver supports this device. | |
@retval EFI_UNSUPPORTED Debug Port device is not supported. | |
@retval EFI_OUT_OF_RESOURCES Fails to allocate memory for device. | |
@retval others Some error occurs. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
DebugPortSupported ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE ControllerHandle, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
EFI_DEVICE_PATH_PROTOCOL *DebugPortVariable; | |
EFI_SERIAL_IO_PROTOCOL *SerialIo; | |
EFI_DEBUGPORT_PROTOCOL *DebugPortInterface; | |
EFI_HANDLE TempHandle; | |
// | |
// Check to see that there's not a debugport protocol already published, | |
// since only one standard UART serial port could be supported by this driver. | |
// | |
if (gBS->LocateProtocol (&gEfiDebugPortProtocolGuid, NULL, (VOID **)&DebugPortInterface) != EFI_NOT_FOUND) { | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// Read DebugPort variable to determine debug port selection and parameters | |
// | |
DebugPortVariable = GetDebugPortVariable (); | |
if (DebugPortVariable != NULL) { | |
// | |
// There's a DEBUGPORT variable, so do LocateDevicePath and check to see if | |
// the closest matching handle matches the controller handle, and if it does, | |
// check to see that the remaining device path has the DebugPort GUIDed messaging | |
// device path only. Otherwise, it's a mismatch and EFI_UNSUPPORTED is returned. | |
// | |
DevicePath = DebugPortVariable; | |
Status = gBS->LocateDevicePath ( | |
&gEfiSerialIoProtocolGuid, | |
&DevicePath, | |
&TempHandle | |
); | |
if ((Status == EFI_SUCCESS) && (TempHandle != ControllerHandle)) { | |
Status = EFI_UNSUPPORTED; | |
} | |
if ((Status == EFI_SUCCESS) && | |
((DevicePath->Type != MESSAGING_DEVICE_PATH) || | |
(DevicePath->SubType != MSG_VENDOR_DP) || | |
(*((UINT16 *)DevicePath->Length) != sizeof (DEBUGPORT_DEVICE_PATH)))) | |
{ | |
Status = EFI_UNSUPPORTED; | |
} | |
if ((Status == EFI_SUCCESS) && !CompareGuid (&gEfiDebugPortDevicePathGuid, (GUID *)(DevicePath + 1))) { | |
Status = EFI_UNSUPPORTED; | |
} | |
FreePool (DebugPortVariable); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
} | |
Status = gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiSerialIoProtocolGuid, | |
(VOID **)&SerialIo, | |
This->DriverBindingHandle, | |
ControllerHandle, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiSerialIoProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
return Status; | |
} | |
/** | |
Binds exclusively to serial io on the controller handle, Produces DebugPort | |
protocol and DevicePath on new handle. | |
@param This Protocol instance pointer. | |
@param ControllerHandle Handle of device to bind driver to. | |
@param RemainingDevicePath Optional parameter use to pick a specific child | |
device to start. | |
@retval EFI_SUCCESS This driver is added to ControllerHandle. | |
@retval EFI_OUT_OF_RESOURCES Fails to allocate memory for device. | |
@retval others Some error occurs. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
DebugPortStart ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE ControllerHandle, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
) | |
{ | |
EFI_STATUS Status; | |
DEBUGPORT_DEVICE_PATH DebugPortDP; | |
EFI_DEVICE_PATH_PROTOCOL EndDP; | |
EFI_DEVICE_PATH_PROTOCOL *Dp1; | |
Status = gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiSerialIoProtocolGuid, | |
(VOID **)&mDebugPortDevice.SerialIoBinding, | |
This->DriverBindingHandle, | |
ControllerHandle, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
mDebugPortDevice.SerialIoDeviceHandle = ControllerHandle; | |
// | |
// Initialize the Serial Io interface... | |
// | |
Status = mDebugPortDevice.SerialIoBinding->SetAttributes ( | |
mDebugPortDevice.SerialIoBinding, | |
mDebugPortDevice.BaudRate, | |
mDebugPortDevice.ReceiveFifoDepth, | |
mDebugPortDevice.Timeout, | |
mDebugPortDevice.Parity, | |
mDebugPortDevice.DataBits, | |
mDebugPortDevice.StopBits | |
); | |
if (EFI_ERROR (Status)) { | |
mDebugPortDevice.BaudRate = 0; | |
mDebugPortDevice.Parity = DefaultParity; | |
mDebugPortDevice.DataBits = 0; | |
mDebugPortDevice.StopBits = DefaultStopBits; | |
mDebugPortDevice.ReceiveFifoDepth = 0; | |
Status = mDebugPortDevice.SerialIoBinding->SetAttributes ( | |
mDebugPortDevice.SerialIoBinding, | |
mDebugPortDevice.BaudRate, | |
mDebugPortDevice.ReceiveFifoDepth, | |
mDebugPortDevice.Timeout, | |
mDebugPortDevice.Parity, | |
mDebugPortDevice.DataBits, | |
mDebugPortDevice.StopBits | |
); | |
if (EFI_ERROR (Status)) { | |
gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiSerialIoProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
return Status; | |
} | |
} | |
mDebugPortDevice.SerialIoBinding->Reset (mDebugPortDevice.SerialIoBinding); | |
// | |
// Create device path instance for DebugPort | |
// | |
DebugPortDP.Header.Type = MESSAGING_DEVICE_PATH; | |
DebugPortDP.Header.SubType = MSG_VENDOR_DP; | |
SetDevicePathNodeLength (&(DebugPortDP.Header), sizeof (DebugPortDP)); | |
CopyGuid (&DebugPortDP.Guid, &gEfiDebugPortDevicePathGuid); | |
Dp1 = DevicePathFromHandle (ControllerHandle); | |
if (Dp1 == NULL) { | |
Dp1 = &EndDP; | |
SetDevicePathEndNode (Dp1); | |
} | |
mDebugPortDevice.DebugPortDevicePath = AppendDevicePathNode (Dp1, (EFI_DEVICE_PATH_PROTOCOL *)&DebugPortDP); | |
if (mDebugPortDevice.DebugPortDevicePath == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Publish DebugPort and Device Path protocols | |
// | |
Status = gBS->InstallMultipleProtocolInterfaces ( | |
&mDebugPortDevice.DebugPortDeviceHandle, | |
&gEfiDevicePathProtocolGuid, | |
mDebugPortDevice.DebugPortDevicePath, | |
&gEfiDebugPortProtocolGuid, | |
&mDebugPortDevice.DebugPortInterface, | |
NULL | |
); | |
if (EFI_ERROR (Status)) { | |
gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiSerialIoProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
return Status; | |
} | |
// | |
// Connect debugport child to serial io | |
// | |
Status = gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiSerialIoProtocolGuid, | |
(VOID **)&mDebugPortDevice.SerialIoBinding, | |
This->DriverBindingHandle, | |
mDebugPortDevice.DebugPortDeviceHandle, | |
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
); | |
if (EFI_ERROR (Status)) { | |
gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiSerialIoProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
return Status; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Stop this driver on ControllerHandle by removing Serial IO protocol on | |
the ControllerHandle. | |
@param This Protocol instance pointer. | |
@param ControllerHandle Handle of device to stop driver on | |
@param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of | |
children is zero stop the entire bus driver. | |
@param ChildHandleBuffer List of Child Handles to Stop. | |
@retval EFI_SUCCESS This driver is removed ControllerHandle. | |
@retval other This driver was not removed from this device. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
DebugPortStop ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE ControllerHandle, | |
IN UINTN NumberOfChildren, | |
IN EFI_HANDLE *ChildHandleBuffer | |
) | |
{ | |
EFI_STATUS Status; | |
if (NumberOfChildren == 0) { | |
// | |
// Close the bus driver | |
// | |
gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiSerialIoProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
mDebugPortDevice.SerialIoBinding = NULL; | |
gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiDevicePathProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
FreePool (mDebugPortDevice.DebugPortDevicePath); | |
return EFI_SUCCESS; | |
} else { | |
// | |
// Disconnect SerialIo child handle | |
// | |
Status = gBS->CloseProtocol ( | |
mDebugPortDevice.SerialIoDeviceHandle, | |
&gEfiSerialIoProtocolGuid, | |
This->DriverBindingHandle, | |
mDebugPortDevice.DebugPortDeviceHandle | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Unpublish our protocols (DevicePath, DebugPort) | |
// | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
mDebugPortDevice.DebugPortDeviceHandle, | |
&gEfiDevicePathProtocolGuid, | |
mDebugPortDevice.DebugPortDevicePath, | |
&gEfiDebugPortProtocolGuid, | |
&mDebugPortDevice.DebugPortInterface, | |
NULL | |
); | |
if (EFI_ERROR (Status)) { | |
gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiSerialIoProtocolGuid, | |
(VOID **)&mDebugPortDevice.SerialIoBinding, | |
This->DriverBindingHandle, | |
mDebugPortDevice.DebugPortDeviceHandle, | |
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
); | |
} else { | |
mDebugPortDevice.DebugPortDeviceHandle = NULL; | |
} | |
} | |
return Status; | |
} | |
/** | |
DebugPort protocol member function. Calls SerialIo:GetControl to flush buffer. | |
We cannot call SerialIo:SetAttributes because it uses pool services, which use | |
locks, which affect TPL, so it's not interrupt context safe or re-entrant. | |
SerialIo:Reset() calls SetAttributes, so it can't be used either. | |
The port itself should be fine since it was set up during initialization. | |
@param This Protocol instance pointer. | |
@return EFI_SUCCESS Always. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
DebugPortReset ( | |
IN EFI_DEBUGPORT_PROTOCOL *This | |
) | |
{ | |
UINTN BufferSize; | |
UINTN BitBucket; | |
while (This->Poll (This) == EFI_SUCCESS) { | |
BufferSize = 1; | |
This->Read (This, 0, &BufferSize, &BitBucket); | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
DebugPort protocol member function. Calls SerialIo:Read() after setting | |
if it's different than the last SerialIo access. | |
@param This Pointer to DebugPort protocol. | |
@param Timeout Timeout value. | |
@param BufferSize On input, the size of Buffer. | |
On output, the amount of data actually written. | |
@param Buffer Pointer to buffer to read. | |
@retval EFI_SUCCESS | |
@retval others | |
**/ | |
EFI_STATUS | |
EFIAPI | |
DebugPortRead ( | |
IN EFI_DEBUGPORT_PROTOCOL *This, | |
IN UINT32 Timeout, | |
IN OUT UINTN *BufferSize, | |
IN VOID *Buffer | |
) | |
{ | |
DEBUGPORT_DEVICE *DebugPortDevice; | |
UINTN LocalBufferSize; | |
EFI_STATUS Status; | |
UINT8 *BufferPtr; | |
DebugPortDevice = DEBUGPORT_DEVICE_FROM_THIS (This); | |
BufferPtr = Buffer; | |
LocalBufferSize = *BufferSize; | |
do { | |
Status = DebugPortDevice->SerialIoBinding->Read ( | |
DebugPortDevice->SerialIoBinding, | |
&LocalBufferSize, | |
BufferPtr | |
); | |
if (Status == EFI_TIMEOUT) { | |
if (Timeout > DEBUGPORT_UART_DEFAULT_TIMEOUT) { | |
Timeout -= DEBUGPORT_UART_DEFAULT_TIMEOUT; | |
} else { | |
Timeout = 0; | |
} | |
} else if (EFI_ERROR (Status)) { | |
break; | |
} | |
BufferPtr += LocalBufferSize; | |
LocalBufferSize = *BufferSize - (BufferPtr - (UINT8 *)Buffer); | |
} while (LocalBufferSize != 0 && Timeout > 0); | |
*BufferSize = (UINTN)BufferPtr - (UINTN)Buffer; | |
return Status; | |
} | |
/** | |
DebugPort protocol member function. Calls SerialIo:Write() Writes 8 bytes at | |
a time and does a GetControl between 8 byte writes to help insure reads are | |
interspersed This is poor-man's flow control. | |
@param This Pointer to DebugPort protocol. | |
@param Timeout Timeout value. | |
@param BufferSize On input, the size of Buffer. | |
On output, the amount of data actually written. | |
@param Buffer Pointer to buffer to read. | |
@retval EFI_SUCCESS The data was written. | |
@retval others Fails when writting datas to debug port device. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
DebugPortWrite ( | |
IN EFI_DEBUGPORT_PROTOCOL *This, | |
IN UINT32 Timeout, | |
IN OUT UINTN *BufferSize, | |
OUT VOID *Buffer | |
) | |
{ | |
DEBUGPORT_DEVICE *DebugPortDevice; | |
UINTN Position; | |
UINTN WriteSize; | |
EFI_STATUS Status; | |
UINT32 SerialControl; | |
Status = EFI_SUCCESS; | |
DebugPortDevice = DEBUGPORT_DEVICE_FROM_THIS (This); | |
WriteSize = 8; | |
for (Position = 0; Position < *BufferSize && !EFI_ERROR (Status); Position += WriteSize) { | |
DebugPortDevice->SerialIoBinding->GetControl ( | |
DebugPortDevice->SerialIoBinding, | |
&SerialControl | |
); | |
if (*BufferSize - Position < 8) { | |
WriteSize = *BufferSize - Position; | |
} | |
Status = DebugPortDevice->SerialIoBinding->Write ( | |
DebugPortDevice->SerialIoBinding, | |
&WriteSize, | |
&((UINT8 *)Buffer)[Position] | |
); | |
} | |
*BufferSize = Position; | |
return Status; | |
} | |
/** | |
DebugPort protocol member function. Calls SerialIo:Write() after setting | |
if it's different than the last SerialIo access. | |
@param This Pointer to DebugPort protocol. | |
@retval EFI_SUCCESS At least 1 character is ready to be read from | |
the DebugPort interface. | |
@retval EFI_NOT_READY There are no characters ready to read from the | |
DebugPort interface | |
@retval EFI_DEVICE_ERROR A hardware failure occurred... (from SerialIo) | |
**/ | |
EFI_STATUS | |
EFIAPI | |
DebugPortPoll ( | |
IN EFI_DEBUGPORT_PROTOCOL *This | |
) | |
{ | |
EFI_STATUS Status; | |
UINT32 SerialControl; | |
DEBUGPORT_DEVICE *DebugPortDevice; | |
DebugPortDevice = DEBUGPORT_DEVICE_FROM_THIS (This); | |
Status = DebugPortDevice->SerialIoBinding->GetControl ( | |
DebugPortDevice->SerialIoBinding, | |
&SerialControl | |
); | |
if (!EFI_ERROR (Status)) { | |
if ((SerialControl & EFI_SERIAL_INPUT_BUFFER_EMPTY) != 0) { | |
Status = EFI_NOT_READY; | |
} else { | |
Status = EFI_SUCCESS; | |
} | |
} | |
return Status; | |
} | |
/** | |
Unload function that is registered in the LoadImage protocol. It un-installs | |
protocols produced and deallocates pool used by the driver. Called by the core | |
when unloading the driver. | |
@param ImageHandle | |
@retval EFI_SUCCESS Unload Debug Port driver successfully. | |
@retval EFI_ABORTED Serial IO is still binding. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
ImageUnloadHandler ( | |
EFI_HANDLE ImageHandle | |
) | |
{ | |
EFI_STATUS Status; | |
VOID *ComponentName; | |
VOID *ComponentName2; | |
if (mDebugPortDevice.SerialIoBinding != NULL) { | |
return EFI_ABORTED; | |
} | |
// | |
// Driver is stopped already. | |
// | |
Status = gBS->HandleProtocol (ImageHandle, &gEfiComponentNameProtocolGuid, &ComponentName); | |
if (EFI_ERROR (Status)) { | |
ComponentName = NULL; | |
} | |
Status = gBS->HandleProtocol (ImageHandle, &gEfiComponentName2ProtocolGuid, &ComponentName2); | |
if (EFI_ERROR (Status)) { | |
ComponentName2 = NULL; | |
} | |
if (ComponentName == NULL) { | |
if (ComponentName2 == NULL) { | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
ImageHandle, | |
&gEfiDriverBindingProtocolGuid, | |
&gDebugPortDriverBinding, | |
NULL | |
); | |
} else { | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
ImageHandle, | |
&gEfiDriverBindingProtocolGuid, | |
&gDebugPortDriverBinding, | |
&gEfiComponentName2ProtocolGuid, | |
ComponentName2, | |
NULL | |
); | |
} | |
} else { | |
if (ComponentName2 == NULL) { | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
ImageHandle, | |
&gEfiDriverBindingProtocolGuid, | |
&gDebugPortDriverBinding, | |
&gEfiComponentNameProtocolGuid, | |
ComponentName, | |
NULL | |
); | |
} else { | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
ImageHandle, | |
&gEfiDriverBindingProtocolGuid, | |
&gDebugPortDriverBinding, | |
&gEfiComponentNameProtocolGuid, | |
ComponentName, | |
&gEfiComponentName2ProtocolGuid, | |
ComponentName2, | |
NULL | |
); | |
} | |
} | |
return Status; | |
} |