/*++ | |
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: | |
DebugPort.c | |
Abstract: | |
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. | |
Revision History | |
--*/ | |
#include "DebugPort.h" | |
// | |
// Misc. functions local to this module | |
// | |
STATIC | |
VOID | |
GetDebugPortVariable ( | |
DEBUGPORT_DEVICE *DebugPortDevice | |
); | |
EFI_STATUS | |
EFIAPI | |
ImageUnloadHandler ( | |
EFI_HANDLE ImageHandle | |
); | |
// | |
// Globals | |
// | |
EFI_DRIVER_BINDING_PROTOCOL gDebugPortDriverBinding = { | |
DebugPortSupported, | |
DebugPortStart, | |
DebugPortStop, | |
DEBUGPORT_DRIVER_VERSION, | |
NULL, | |
NULL | |
}; | |
DEBUGPORT_DEVICE *gDebugPortDevice; | |
static UINT32 mHid16550; | |
static UINT32 mHidStdPcComPort; | |
// | |
// implementation code | |
// | |
EFI_STATUS | |
EFIAPI | |
InitializeDebugPortDriver ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
/*++ | |
Routine Description: | |
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. | |
Creates debugport and devicepath protocols on new handle. | |
Arguments: | |
ImageHandle, | |
SystemTable | |
Returns: | |
EFI_UNSUPPORTED | |
EFI_OUT_OF_RESOURCES | |
--*/ | |
{ | |
mHid16550 = EFI_ACPI_16550UART_HID; | |
mHidStdPcComPort = EFI_ACPI_PC_COMPORT_HID; | |
// | |
// Allocate and Initialize dev structure | |
// | |
gDebugPortDevice = AllocateZeroPool (sizeof (DEBUGPORT_DEVICE)); | |
if (gDebugPortDevice == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Fill in static and default pieces of device structure first. | |
// | |
gDebugPortDevice->Signature = DEBUGPORT_DEVICE_SIGNATURE; | |
gDebugPortDevice->DebugPortInterface.Reset = DebugPortReset; | |
gDebugPortDevice->DebugPortInterface.Read = DebugPortRead; | |
gDebugPortDevice->DebugPortInterface.Write = DebugPortWrite; | |
gDebugPortDevice->DebugPortInterface.Poll = DebugPortPoll; | |
gDebugPortDevice->BaudRate = DEBUGPORT_UART_DEFAULT_BAUDRATE; | |
gDebugPortDevice->ReceiveFifoDepth = DEBUGPORT_UART_DEFAULT_FIFO_DEPTH; | |
gDebugPortDevice->Timeout = DEBUGPORT_UART_DEFAULT_TIMEOUT; | |
gDebugPortDevice->Parity = DEBUGPORT_UART_DEFAULT_PARITY; | |
gDebugPortDevice->DataBits = DEBUGPORT_UART_DEFAULT_DATA_BITS; | |
gDebugPortDevice->StopBits = DEBUGPORT_UART_DEFAULT_STOP_BITS; | |
return EFI_SUCCESS; | |
} | |
// | |
// DebugPort driver binding member functions... | |
// | |
EFI_STATUS | |
EFIAPI | |
DebugPortSupported ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE ControllerHandle, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
) | |
/*++ | |
Routine Description: | |
Checks to see that there's not already a DebugPort interface somewhere. If so, | |
fail. | |
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. | |
Arguments: | |
This | |
ControllerHandle | |
RemainingDevicePath | |
Returns: | |
EFI_UNSUPPORTED | |
EFI_OUT_OF_RESOURCES | |
EFI_SUCCESS | |
--*/ | |
{ | |
EFI_STATUS Status; | |
EFI_DEVICE_PATH_PROTOCOL *Dp1; | |
EFI_DEVICE_PATH_PROTOCOL *Dp2; | |
EFI_SERIAL_IO_PROTOCOL *SerialIo; | |
EFI_DEBUGPORT_PROTOCOL *DebugPortInterface; | |
EFI_HANDLE TempHandle; | |
// | |
// Check to see that there's not a debugport protocol already published | |
// | |
if (gBS->LocateProtocol (&gEfiDebugPortProtocolGuid, NULL, (VOID **) &DebugPortInterface) != EFI_NOT_FOUND) { | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// Read DebugPort variable to determine debug port selection and parameters | |
// | |
GetDebugPortVariable (gDebugPortDevice); | |
if (gDebugPortDevice->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. | |
// | |
Dp1 = DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL *) gDebugPortDevice->DebugPortVariable); | |
if (Dp1 == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Dp2 = Dp1; | |
Status = gBS->LocateDevicePath ( | |
&gEfiSerialIoProtocolGuid, | |
&Dp2, | |
&TempHandle | |
); | |
if (Status == EFI_SUCCESS && TempHandle != ControllerHandle) { | |
Status = EFI_UNSUPPORTED; | |
} | |
if (Status == EFI_SUCCESS && (Dp2->Type != 3 || Dp2->SubType != 10 || *((UINT16 *) Dp2->Length) != 20)) { | |
Status = EFI_UNSUPPORTED; | |
} | |
if (Status == EFI_SUCCESS && CompareMem (&gEfiDebugPortDevicePathGuid, Dp2 + 1, sizeof (EFI_GUID))) { | |
Status = EFI_UNSUPPORTED; | |
} | |
gBS->FreePool (Dp1); | |
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; | |
} | |
gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiSerialIoProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
EFIAPI | |
DebugPortStart ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE ControllerHandle, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
) | |
/*++ | |
Routine Description: | |
Binds exclusively to serial io on the controller handle. Produces DebugPort | |
protocol and DevicePath on new handle. | |
Arguments: | |
This | |
ControllerHandle | |
RemainingDevicePath | |
Returns: | |
EFI_OUT_OF_RESOURCES | |
EFI_SUCCESS | |
--*/ | |
{ | |
EFI_STATUS Status; | |
DEBUGPORT_DEVICE_PATH DebugPortDP; | |
EFI_DEVICE_PATH_PROTOCOL EndDP; | |
EFI_DEVICE_PATH_PROTOCOL *Dp1; | |
Status = gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiSerialIoProtocolGuid, | |
(VOID **) &gDebugPortDevice->SerialIoBinding, | |
This->DriverBindingHandle, | |
ControllerHandle, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
gDebugPortDevice->SerialIoDeviceHandle = ControllerHandle; | |
// | |
// Initialize the Serial Io interface... | |
// | |
Status = gDebugPortDevice->SerialIoBinding->SetAttributes ( | |
gDebugPortDevice->SerialIoBinding, | |
gDebugPortDevice->BaudRate, | |
gDebugPortDevice->ReceiveFifoDepth, | |
gDebugPortDevice->Timeout, | |
gDebugPortDevice->Parity, | |
gDebugPortDevice->DataBits, | |
gDebugPortDevice->StopBits | |
); | |
if (EFI_ERROR (Status)) { | |
gDebugPortDevice->BaudRate = 0; | |
gDebugPortDevice->Parity = DefaultParity; | |
gDebugPortDevice->DataBits = 0; | |
gDebugPortDevice->StopBits = DefaultStopBits; | |
gDebugPortDevice->ReceiveFifoDepth = 0; | |
Status = gDebugPortDevice->SerialIoBinding->SetAttributes ( | |
gDebugPortDevice->SerialIoBinding, | |
gDebugPortDevice->BaudRate, | |
gDebugPortDevice->ReceiveFifoDepth, | |
gDebugPortDevice->Timeout, | |
gDebugPortDevice->Parity, | |
gDebugPortDevice->DataBits, | |
gDebugPortDevice->StopBits | |
); | |
if (EFI_ERROR (Status)) { | |
gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiSerialIoProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
return Status; | |
} | |
} | |
gDebugPortDevice->SerialIoBinding->Reset (gDebugPortDevice->SerialIoBinding); | |
// | |
// Create device path instance for DebugPort | |
// | |
DebugPortDP.Header.Type = MESSAGING_DEVICE_PATH; | |
DebugPortDP.Header.SubType = MSG_VENDOR_DP; | |
SetDevicePathNodeLength (&(DebugPortDP.Header), sizeof (DebugPortDP)); | |
gBS->CopyMem (&DebugPortDP.Guid, &gEfiDebugPortDevicePathGuid, sizeof (EFI_GUID)); | |
Dp1 = DevicePathFromHandle (ControllerHandle); | |
if (Dp1 == NULL) { | |
Dp1 = &EndDP; | |
SetDevicePathEndNode (Dp1); | |
} | |
gDebugPortDevice->DebugPortDevicePath = AppendDevicePathNode (Dp1, (EFI_DEVICE_PATH_PROTOCOL *) &DebugPortDP); | |
if (gDebugPortDevice->DebugPortDevicePath == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Publish DebugPort and Device Path protocols | |
// | |
Status = gBS->InstallMultipleProtocolInterfaces ( | |
&gDebugPortDevice->DebugPortDeviceHandle, | |
&gEfiDevicePathProtocolGuid, | |
gDebugPortDevice->DebugPortDevicePath, | |
&gEfiDebugPortProtocolGuid, | |
&gDebugPortDevice->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 **) &gDebugPortDevice->SerialIoBinding, | |
This->DriverBindingHandle, | |
gDebugPortDevice->DebugPortDeviceHandle, | |
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG_CODE ( | |
UINTN BufferSize; | |
BufferSize = 48; | |
DebugPortWrite ( | |
&gDebugPortDevice->DebugPortInterface, | |
0, | |
&BufferSize, | |
"DebugPort driver failed to open child controller\n\n" | |
); | |
); | |
gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiSerialIoProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
return Status; | |
} | |
DEBUG_CODE ( | |
UINTN BufferSize; | |
BufferSize = 38; | |
DebugPortWrite ( | |
&gDebugPortDevice->DebugPortInterface, | |
0, | |
&BufferSize, | |
"Hello World from the DebugPort driver\n\n" | |
); | |
); | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
EFIAPI | |
DebugPortStop ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE ControllerHandle, | |
IN UINTN NumberOfChildren, | |
IN EFI_HANDLE *ChildHandleBuffer | |
) | |
/*++ | |
Routine Description: | |
We're never intending to be stopped via the driver model so this just returns | |
EFI_UNSUPPORTED | |
Arguments: | |
Per EFI 1.10 driver model | |
Returns: | |
EFI_UNSUPPORTED | |
EFI_SUCCESS | |
--*/ | |
{ | |
EFI_STATUS Status; | |
if (NumberOfChildren == 0) { | |
// | |
// Close the bus driver | |
// | |
gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiSerialIoProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
gDebugPortDevice->SerialIoBinding = NULL; | |
gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiDevicePathProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
gBS->FreePool (gDebugPortDevice->DebugPortDevicePath); | |
return EFI_SUCCESS; | |
} else { | |
// | |
// Disconnect SerialIo child handle | |
// | |
Status = gBS->CloseProtocol ( | |
gDebugPortDevice->SerialIoDeviceHandle, | |
&gEfiSerialIoProtocolGuid, | |
This->DriverBindingHandle, | |
gDebugPortDevice->DebugPortDeviceHandle | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Unpublish our protocols (DevicePath, DebugPort) | |
// | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
gDebugPortDevice->DebugPortDeviceHandle, | |
&gEfiDevicePathProtocolGuid, | |
gDebugPortDevice->DebugPortDevicePath, | |
&gEfiDebugPortProtocolGuid, | |
&gDebugPortDevice->DebugPortInterface, | |
NULL | |
); | |
if (EFI_ERROR (Status)) { | |
gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiSerialIoProtocolGuid, | |
(VOID **) &gDebugPortDevice->SerialIoBinding, | |
This->DriverBindingHandle, | |
gDebugPortDevice->DebugPortDeviceHandle, | |
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
); | |
} else { | |
gDebugPortDevice->DebugPortDeviceHandle = NULL; | |
} | |
} | |
return Status; | |
} | |
// | |
// Debugport protocol member functions | |
// | |
EFI_STATUS | |
EFIAPI | |
DebugPortReset ( | |
IN EFI_DEBUGPORT_PROTOCOL *This | |
) | |
/*++ | |
Routine Description: | |
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. | |
Arguments: | |
This | |
Returns: | |
EFI_SUCCESS | |
--*/ | |
{ | |
DEBUGPORT_DEVICE *DebugPortDevice; | |
UINTN BufferSize; | |
UINTN BitBucket; | |
DebugPortDevice = DEBUGPORT_DEVICE_FROM_THIS (This); | |
while (This->Poll (This) == EFI_SUCCESS) { | |
BufferSize = 1; | |
This->Read (This, 0, &BufferSize, &BitBucket); | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
EFIAPI | |
DebugPortRead ( | |
IN EFI_DEBUGPORT_PROTOCOL *This, | |
IN UINT32 Timeout, | |
IN OUT UINTN *BufferSize, | |
IN VOID *Buffer | |
) | |
/*++ | |
Routine Description: | |
DebugPort protocol member function. Calls SerialIo:Read() after setting | |
if it's different than the last SerialIo access. | |
Arguments: | |
IN EFI_DEBUGPORT_PROTOCOL *This | |
IN UINT32 Timeout, | |
IN OUT UINTN *BufferSize, | |
IN VOID *Buffer | |
Returns: | |
EFI_STATUS | |
--*/ | |
{ | |
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 - (UINT8 *) Buffer); | |
return Status; | |
} | |
EFI_STATUS | |
EFIAPI | |
DebugPortWrite ( | |
IN EFI_DEBUGPORT_PROTOCOL *This, | |
IN UINT32 Timeout, | |
IN OUT UINTN *BufferSize, | |
OUT VOID *Buffer | |
) | |
/*++ | |
Routine Description: | |
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.. | |
Arguments: | |
This - Pointer to DebugPort protocol | |
Timeout - Timeout value | |
BufferSize - On input, the size of Buffer. | |
On output, the amount of data actually written. | |
Buffer - Pointer to buffer to write | |
Returns: | |
EFI_SUCCESS - The data was written. | |
EFI_DEVICE_ERROR - The device reported an error. | |
EFI_TIMEOUT - The data write was stopped due to a timeout. | |
--*/ | |
{ | |
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; | |
} | |
EFI_STATUS | |
EFIAPI | |
DebugPortPoll ( | |
IN EFI_DEBUGPORT_PROTOCOL *This | |
) | |
/*++ | |
Routine Description: | |
DebugPort protocol member function. Calls SerialIo:Write() after setting | |
if it's different than the last SerialIo access. | |
Arguments: | |
IN EFI_DEBUGPORT_PROTOCOL *This | |
Returns: | |
EFI_SUCCESS - At least 1 character is ready to be read from the DebugPort interface | |
EFI_NOT_READY - There are no characters ready to read from the DebugPort interface | |
EFI_DEVICE_ERROR - A hardware failure occured... (from SerialIo) | |
--*/ | |
{ | |
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) { | |
Status = EFI_NOT_READY; | |
} else { | |
Status = EFI_SUCCESS; | |
} | |
} | |
return Status; | |
} | |
// | |
// Misc. functions local to this module.. | |
// | |
STATIC | |
VOID | |
GetDebugPortVariable ( | |
DEBUGPORT_DEVICE *DebugPortDevice | |
) | |
/*++ | |
Routine Description: | |
Local worker function to obtain device path information from DebugPort variable. | |
Records requested settings in DebugPort device structure. | |
Arguments: | |
DEBUGPORT_DEVICE *DebugPortDevice, | |
Returns: | |
Nothing | |
--*/ | |
{ | |
UINTN DataSize; | |
EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
EFI_STATUS Status; | |
DataSize = 0; | |
Status = gRT->GetVariable ( | |
(CHAR16 *) EFI_DEBUGPORT_VARIABLE_NAME, | |
&gEfiDebugPortVariableGuid, | |
NULL, | |
&DataSize, | |
DebugPortDevice->DebugPortVariable | |
); | |
if (Status == EFI_BUFFER_TOO_SMALL) { | |
if (gDebugPortDevice->DebugPortVariable != NULL) { | |
gBS->FreePool (gDebugPortDevice->DebugPortVariable); | |
} | |
DebugPortDevice->DebugPortVariable = AllocatePool (DataSize); | |
if (DebugPortDevice->DebugPortVariable != NULL) { | |
gRT->GetVariable ( | |
(CHAR16 *) EFI_DEBUGPORT_VARIABLE_NAME, | |
&gEfiDebugPortVariableGuid, | |
NULL, | |
&DataSize, | |
DebugPortDevice->DebugPortVariable | |
); | |
DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DebugPortDevice->DebugPortVariable; | |
while (!EfiIsDevicePathEnd (DevicePath) && !EfiIsUartDevicePath (DevicePath)) { | |
DevicePath = EfiNextDevicePathNode (DevicePath); | |
} | |
if (EfiIsDevicePathEnd (DevicePath)) { | |
gBS->FreePool (gDebugPortDevice->DebugPortVariable); | |
DebugPortDevice->DebugPortVariable = NULL; | |
} else { | |
gBS->CopyMem ( | |
&DebugPortDevice->BaudRate, | |
&((UART_DEVICE_PATH *) DevicePath)->BaudRate, | |
sizeof (((UART_DEVICE_PATH *) DevicePath)->BaudRate) | |
); | |
DebugPortDevice->ReceiveFifoDepth = DEBUGPORT_UART_DEFAULT_FIFO_DEPTH; | |
DebugPortDevice->Timeout = DEBUGPORT_UART_DEFAULT_TIMEOUT; | |
gBS->CopyMem ( | |
&DebugPortDevice->Parity, | |
&((UART_DEVICE_PATH *) DevicePath)->Parity, | |
sizeof (((UART_DEVICE_PATH *) DevicePath)->Parity) | |
); | |
gBS->CopyMem ( | |
&DebugPortDevice->DataBits, | |
&((UART_DEVICE_PATH *) DevicePath)->DataBits, | |
sizeof (((UART_DEVICE_PATH *) DevicePath)->DataBits) | |
); | |
gBS->CopyMem ( | |
&DebugPortDevice->StopBits, | |
&((UART_DEVICE_PATH *) DevicePath)->StopBits, | |
sizeof (((UART_DEVICE_PATH *) DevicePath)->StopBits) | |
); | |
} | |
} | |
} | |
} | |
EFI_STATUS | |
EFIAPI | |
ImageUnloadHandler ( | |
EFI_HANDLE ImageHandle | |
) | |
/*++ | |
Routine Description: | |
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. | |
Arguments: | |
EFI_HANDLE ImageHandle | |
Returns: | |
EFI_SUCCESS | |
--*/ | |
{ | |
EFI_STATUS Status; | |
if (gDebugPortDevice->SerialIoBinding != NULL) { | |
return EFI_ABORTED; | |
} | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
ImageHandle, | |
&gEfiDriverBindingProtocolGuid, | |
&gDebugPortDevice->DriverBindingInterface, | |
&gEfiComponentNameProtocolGuid, | |
&gDebugPortDevice->ComponentNameInterface, | |
NULL | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Clean up allocations | |
// | |
if (gDebugPortDevice->DebugPortVariable != NULL) { | |
gBS->FreePool (gDebugPortDevice->DebugPortVariable); | |
} | |
gBS->FreePool (gDebugPortDevice); | |
return EFI_SUCCESS; | |
} |