/*++ | |
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: | |
Terminal.c | |
Abstract: | |
Revision History: | |
--*/ | |
#include "Terminal.h" | |
#include <Common/StatusCode.h> | |
// | |
// Function Prototypes | |
// | |
EFI_STATUS | |
EFIAPI | |
TerminalDriverBindingSupported ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE Controller, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
); | |
EFI_STATUS | |
EFIAPI | |
TerminalDriverBindingStart ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE Controller, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
); | |
EFI_STATUS | |
EFIAPI | |
TerminalDriverBindingStop ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE Controller, | |
IN UINTN NumberOfChildren, | |
IN EFI_HANDLE *ChildHandleBuffer | |
); | |
// | |
// Globals | |
// | |
EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = { | |
TerminalDriverBindingSupported, | |
TerminalDriverBindingStart, | |
TerminalDriverBindingStop, | |
0x10, | |
NULL, | |
NULL | |
}; | |
EFI_STATUS | |
EFIAPI | |
TerminalDriverBindingSupported ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE Controller, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; | |
EFI_SERIAL_IO_PROTOCOL *SerialIo; | |
VENDOR_DEVICE_PATH *Node; | |
// | |
// If remaining device path is not NULL, then make sure it is a | |
// device path that describes a terminal communications protocol. | |
// | |
if (RemainingDevicePath != NULL) { | |
Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath; | |
if (Node->Header.Type != MESSAGING_DEVICE_PATH || | |
Node->Header.SubType != MSG_VENDOR_DP || | |
DevicePathNodeLength(&Node->Header) != sizeof(VENDOR_DEVICE_PATH)) { | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// only supports PC ANSI, VT100, VT100+ and VT-UTF8 terminal types | |
// | |
if (!CompareGuid (&Node->Guid, &gEfiPcAnsiGuid) && | |
!CompareGuid (&Node->Guid, &gEfiVT100Guid) && | |
!CompareGuid (&Node->Guid, &gEfiVT100PlusGuid) && | |
!CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) { | |
return EFI_UNSUPPORTED; | |
} | |
} | |
// | |
// Open the IO Abstraction(s) needed to perform the supported test | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiDevicePathProtocolGuid, | |
(VOID **) &ParentDevicePath, | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (Status == EFI_ALREADY_STARTED) { | |
return EFI_SUCCESS; | |
} | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
gBS->CloseProtocol ( | |
Controller, | |
&gEfiDevicePathProtocolGuid, | |
This->DriverBindingHandle, | |
Controller | |
); | |
// | |
// The Controller must support the Serial I/O Protocol. | |
// This driver is a bus driver with at most 1 child device, so it is | |
// ok for it to be already started. | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiSerialIoProtocolGuid, | |
(VOID **) &SerialIo, | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (Status == EFI_ALREADY_STARTED) { | |
return EFI_SUCCESS; | |
} | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Close the I/O Abstraction(s) used to perform the supported test | |
// | |
gBS->CloseProtocol ( | |
Controller, | |
&gEfiSerialIoProtocolGuid, | |
This->DriverBindingHandle, | |
Controller | |
); | |
return Status; | |
} | |
EFI_STATUS | |
EFIAPI | |
TerminalDriverBindingStart ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE Controller, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
) | |
/*++ | |
Routine Description: | |
Start the controller. | |
Arguments: | |
This - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. | |
Controller - The handle of the controller to start. | |
RemainingDevicePath - A pointer to the remaining portion of a devcie path. | |
Returns: | |
EFI_SUCCESS. | |
--*/ | |
{ | |
EFI_STATUS Status; | |
EFI_SERIAL_IO_PROTOCOL *SerialIo; | |
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; | |
VENDOR_DEVICE_PATH *Node; | |
VENDOR_DEVICE_PATH *DefaultNode; | |
EFI_SERIAL_IO_MODE *Mode; | |
UINTN SerialInTimeOut; | |
TERMINAL_DEV *TerminalDevice; | |
UINT8 TerminalType; | |
EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; | |
UINTN EntryCount; | |
UINTN Index; | |
EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
TerminalDevice = NULL; | |
DefaultNode = NULL; | |
// | |
// Get the Device Path Protocol to build the device path of the child device | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiDevicePathProtocolGuid, | |
(VOID **) &ParentDevicePath, | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { | |
return Status; | |
} | |
// | |
// Report that the remote terminal is being enabled | |
// | |
DevicePath = ParentDevicePath; | |
REPORT_STATUS_CODE_WITH_DEVICE_PATH ( | |
EFI_PROGRESS_CODE, | |
EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_ENABLE, | |
DevicePath | |
); | |
// | |
// Open the Serial I/O Protocol BY_DRIVER. It might already be started. | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiSerialIoProtocolGuid, | |
(VOID **) &SerialIo, | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { | |
return Status; | |
} | |
if (Status != EFI_ALREADY_STARTED) { | |
// | |
// If Serial I/O is not already open by this driver, then tag the handle | |
// with the Terminal Driver GUID and update the ConInDev, ConOutDev, and | |
// StdErrDev variables with the list of possible terminal types on this | |
// serial port. | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiCallerIdGuid, | |
NULL, | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_TEST_PROTOCOL | |
); | |
if (EFI_ERROR (Status)) { | |
Status = gBS->InstallMultipleProtocolInterfaces ( | |
&Controller, | |
&gEfiCallerIdGuid, | |
DuplicateDevicePath (ParentDevicePath), | |
NULL | |
); | |
if (EFI_ERROR (Status)) { | |
goto Error; | |
} | |
// | |
// if the serial device is a hot plug device, do not update the | |
// ConInDev, ConOutDev, and StdErrDev variables. | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiHotPlugDeviceGuid, | |
NULL, | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_TEST_PROTOCOL | |
); | |
if (EFI_ERROR (Status)) { | |
TerminalUpdateConsoleDevVariable ((CHAR16 *)VarConsoleInpDev, ParentDevicePath); | |
TerminalUpdateConsoleDevVariable ((CHAR16 *)VarConsoleOutDev, ParentDevicePath); | |
TerminalUpdateConsoleDevVariable ((CHAR16 *)VarErrorOutDev, ParentDevicePath); | |
} | |
} | |
} | |
// | |
// Make sure a child handle does not already exist. This driver can only | |
// produce one child per serial port. | |
// | |
Status = gBS->OpenProtocolInformation ( | |
Controller, | |
&gEfiSerialIoProtocolGuid, | |
&OpenInfoBuffer, | |
&EntryCount | |
); | |
if (!EFI_ERROR (Status)) { | |
Status = EFI_SUCCESS; | |
for (Index = 0; Index < EntryCount; Index++) { | |
if (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) { | |
Status = EFI_ALREADY_STARTED; | |
} | |
} | |
gBS->FreePool (OpenInfoBuffer); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
} | |
// | |
// If RemainingDevicePath is NULL, then create default device path node | |
// | |
if (RemainingDevicePath == NULL) { | |
DefaultNode = AllocatePool (sizeof (VENDOR_DEVICE_PATH)); | |
if (DefaultNode == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Error; | |
} | |
CopyMem (&DefaultNode->Guid, &gEfiPcAnsiGuid, sizeof (EFI_GUID)); | |
RemainingDevicePath = (EFI_DEVICE_PATH_PROTOCOL*) DefaultNode; | |
} | |
// | |
// Use the RemainingDevicePath to determine the terminal type | |
// | |
Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath; | |
if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) { | |
TerminalType = PcAnsiType; | |
} else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) { | |
TerminalType = VT100Type; | |
} else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) { | |
TerminalType = VT100PlusType; | |
} else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) { | |
TerminalType = VTUTF8Type; | |
} else { | |
goto Error; | |
} | |
// | |
// Initialize the Terminal Dev | |
// | |
TerminalDevice = AllocatePool (sizeof (TERMINAL_DEV)); | |
if (TerminalDevice == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Error; | |
} | |
ZeroMem (TerminalDevice, sizeof (TERMINAL_DEV)); | |
TerminalDevice->Signature = TERMINAL_DEV_SIGNATURE; | |
TerminalDevice->TerminalType = TerminalType; | |
TerminalDevice->SerialIo = SerialIo; | |
// | |
// Simple Input Protocol | |
// | |
TerminalDevice->SimpleInput.Reset = TerminalConInReset; | |
TerminalDevice->SimpleInput.ReadKeyStroke = TerminalConInReadKeyStroke; | |
Status = gBS->CreateEvent ( | |
EFI_EVENT_NOTIFY_WAIT, | |
EFI_TPL_NOTIFY, | |
TerminalConInWaitForKey, | |
&TerminalDevice->SimpleInput, | |
&TerminalDevice->SimpleInput.WaitForKey | |
); | |
if (EFI_ERROR (Status)) { | |
goto Error; | |
} | |
// | |
// initialize the FIFO buffer used for accommodating | |
// the pre-read pending characters | |
// | |
InitializeRawFiFo (TerminalDevice); | |
InitializeUnicodeFiFo (TerminalDevice); | |
InitializeEfiKeyFiFo (TerminalDevice); | |
// | |
// Set the timeout value of serial buffer for | |
// keystroke response performance issue | |
// | |
Mode = TerminalDevice->SerialIo->Mode; | |
SerialInTimeOut = 0; | |
if (Mode->BaudRate != 0) { | |
SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate; | |
} | |
Status = TerminalDevice->SerialIo->SetAttributes ( | |
TerminalDevice->SerialIo, | |
Mode->BaudRate, | |
Mode->ReceiveFifoDepth, | |
(UINT32) SerialInTimeOut, | |
Mode->Parity, | |
(UINT8) Mode->DataBits, | |
Mode->StopBits | |
); | |
if (EFI_ERROR (Status)) { | |
// | |
// if set attributes operation fails, invalidate | |
// the value of SerialInTimeOut,thus make it | |
// inconsistent with the default timeout value | |
// of serial buffer. This will invoke the recalculation | |
// in the readkeystroke routine. | |
// | |
TerminalDevice->SerialInTimeOut = 0; | |
} else { | |
TerminalDevice->SerialInTimeOut = SerialInTimeOut; | |
} | |
// | |
// Build the device path for the child device | |
// | |
Status = SetTerminalDevicePath ( | |
TerminalDevice->TerminalType, | |
ParentDevicePath, | |
&TerminalDevice->DevicePath | |
); | |
if (EFI_ERROR (Status)) { | |
goto Error; | |
} | |
DevicePath = TerminalDevice->DevicePath; | |
Status = TerminalDevice->SimpleInput.Reset ( | |
&TerminalDevice->SimpleInput, | |
FALSE | |
); | |
if (EFI_ERROR (Status)) { | |
// | |
// Need to report Error Code first | |
// | |
goto ReportError; | |
} | |
// | |
// Simple Text Output Protocol | |
// | |
TerminalDevice->SimpleTextOutput.Reset = TerminalConOutReset; | |
TerminalDevice->SimpleTextOutput.OutputString = TerminalConOutOutputString; | |
TerminalDevice->SimpleTextOutput.TestString = TerminalConOutTestString; | |
TerminalDevice->SimpleTextOutput.QueryMode = TerminalConOutQueryMode; | |
TerminalDevice->SimpleTextOutput.SetMode = TerminalConOutSetMode; | |
TerminalDevice->SimpleTextOutput.SetAttribute = TerminalConOutSetAttribute; | |
TerminalDevice->SimpleTextOutput.ClearScreen = TerminalConOutClearScreen; | |
TerminalDevice->SimpleTextOutput.SetCursorPosition = TerminalConOutSetCursorPosition; | |
TerminalDevice->SimpleTextOutput.EnableCursor = TerminalConOutEnableCursor; | |
TerminalDevice->SimpleTextOutput.Mode = &TerminalDevice->SimpleTextOutputMode; | |
TerminalDevice->SimpleTextOutputMode.MaxMode = 1; | |
// | |
// For terminal devices, cursor is always visible | |
// | |
TerminalDevice->SimpleTextOutputMode.CursorVisible = TRUE; | |
TerminalDevice->SimpleTextOutputMode.Attribute = EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK); | |
Status = TerminalDevice->SimpleTextOutput.Reset ( | |
&TerminalDevice->SimpleTextOutput, | |
FALSE | |
); | |
if (EFI_ERROR (Status)) { | |
goto ReportError; | |
} | |
Status = TerminalDevice->SimpleTextOutput.SetMode ( | |
&TerminalDevice->SimpleTextOutput, | |
0 | |
); | |
if (EFI_ERROR (Status)) { | |
goto ReportError; | |
} | |
Status = TerminalDevice->SimpleTextOutput.EnableCursor ( | |
&TerminalDevice->SimpleTextOutput, | |
TRUE | |
); | |
if (EFI_ERROR (Status)) { | |
goto ReportError; | |
} | |
// | |
// | |
// | |
TerminalDevice->InputState = INPUT_STATE_DEFAULT; | |
TerminalDevice->ResetState = RESET_STATE_DEFAULT; | |
Status = gBS->CreateEvent ( | |
EFI_EVENT_TIMER, | |
EFI_TPL_CALLBACK, | |
NULL, | |
NULL, | |
&TerminalDevice->TwoSecondTimeOut | |
); | |
// | |
// Build the component name for the child device | |
// | |
TerminalDevice->ControllerNameTable = NULL; | |
switch (TerminalDevice->TerminalType) { | |
case PcAnsiType: | |
AddUnicodeString ( | |
"eng", | |
gTerminalComponentName.SupportedLanguages, | |
&TerminalDevice->ControllerNameTable, | |
(CHAR16 *)L"PC-ANSI Serial Console" | |
); | |
break; | |
case VT100Type: | |
AddUnicodeString ( | |
"eng", | |
gTerminalComponentName.SupportedLanguages, | |
&TerminalDevice->ControllerNameTable, | |
(CHAR16 *)L"VT-100 Serial Console" | |
); | |
break; | |
case VT100PlusType: | |
AddUnicodeString ( | |
"eng", | |
gTerminalComponentName.SupportedLanguages, | |
&TerminalDevice->ControllerNameTable, | |
(CHAR16 *)L"VT-100+ Serial Console" | |
); | |
break; | |
case VTUTF8Type: | |
AddUnicodeString ( | |
"eng", | |
gTerminalComponentName.SupportedLanguages, | |
&TerminalDevice->ControllerNameTable, | |
(CHAR16 *)L"VT-UTF8 Serial Console" | |
); | |
break; | |
} | |
// | |
// Install protocol interfaces for the serial device. | |
// | |
Status = gBS->InstallMultipleProtocolInterfaces ( | |
&TerminalDevice->Handle, | |
&gEfiDevicePathProtocolGuid, | |
TerminalDevice->DevicePath, | |
&gEfiSimpleTextInProtocolGuid, | |
&TerminalDevice->SimpleInput, | |
&gEfiSimpleTextOutProtocolGuid, | |
&TerminalDevice->SimpleTextOutput, | |
NULL | |
); | |
if (EFI_ERROR (Status)) { | |
goto Error; | |
} | |
// | |
// if the serial device is a hot plug device, attaches the HotPlugGuid | |
// onto the terminal device handle. | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiHotPlugDeviceGuid, | |
NULL, | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_TEST_PROTOCOL | |
); | |
if (!EFI_ERROR (Status)) { | |
Status = gBS->InstallMultipleProtocolInterfaces ( | |
&TerminalDevice->Handle, | |
&gEfiHotPlugDeviceGuid, | |
NULL, | |
NULL | |
); | |
} | |
// | |
// Register the Parent-Child relationship via | |
// EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiSerialIoProtocolGuid, | |
(VOID **) &TerminalDevice->SerialIo, | |
This->DriverBindingHandle, | |
TerminalDevice->Handle, | |
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
); | |
if (EFI_ERROR (Status)) { | |
goto Error; | |
} | |
if (DefaultNode != NULL) { | |
gBS->FreePool (DefaultNode); | |
} | |
return EFI_SUCCESS; | |
ReportError: | |
// | |
// Report error code before exiting | |
// | |
REPORT_STATUS_CODE_WITH_DEVICE_PATH ( | |
EFI_ERROR_CODE | EFI_ERROR_MINOR, | |
EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR, | |
DevicePath | |
); | |
Error: | |
// | |
// Use the Stop() function to free all resources allocated in Start() | |
// | |
if (TerminalDevice != NULL) { | |
if (TerminalDevice->Handle != NULL) { | |
This->Stop (This, Controller, 1, &TerminalDevice->Handle); | |
} else { | |
if (TerminalDevice->TwoSecondTimeOut != NULL) { | |
gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut); | |
} | |
if (TerminalDevice->SimpleInput.WaitForKey != NULL) { | |
gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey); | |
} | |
if (TerminalDevice->ControllerNameTable != NULL) { | |
FreeUnicodeStringTable (TerminalDevice->ControllerNameTable); | |
} | |
if (TerminalDevice->DevicePath != NULL) { | |
gBS->FreePool (TerminalDevice->DevicePath); | |
} | |
gBS->FreePool (TerminalDevice); | |
} | |
} | |
if (DefaultNode != NULL) { | |
gBS->FreePool (DefaultNode); | |
} | |
This->Stop (This, Controller, 0, NULL); | |
return Status; | |
} | |
EFI_STATUS | |
EFIAPI | |
TerminalDriverBindingStop ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE Controller, | |
IN UINTN NumberOfChildren, | |
IN EFI_HANDLE *ChildHandleBuffer | |
) | |
/*++ | |
Routine Description: | |
Stop a device controller. | |
Arguments: | |
This - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. | |
Controller - A handle to the device being stopped. | |
NumberOfChildren - The number of child device handles in ChildHandleBuffer. | |
ChildHandleBuffer - An array of child handles to be freed. | |
Returns: | |
EFI_SUCCESS - Operation successful. | |
EFI_DEVICE_ERROR - Devices error. | |
--*/ | |
{ | |
EFI_STATUS Status; | |
UINTN Index; | |
BOOLEAN AllChildrenStopped; | |
EFI_SIMPLE_TEXT_OUT_PROTOCOL *SimpleTextOutput; | |
TERMINAL_DEV *TerminalDevice; | |
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; | |
EFI_SERIAL_IO_PROTOCOL *SerialIo; | |
EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
Status = gBS->HandleProtocol ( | |
Controller, | |
&gEfiDevicePathProtocolGuid, | |
(VOID **) &DevicePath | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Report that the remote terminal is being disabled | |
// | |
REPORT_STATUS_CODE_WITH_DEVICE_PATH ( | |
EFI_PROGRESS_CODE, | |
EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_DISABLE, | |
DevicePath | |
); | |
// | |
// Complete all outstanding transactions to Controller. | |
// Don't allow any new transaction to Controller to be started. | |
// | |
if (NumberOfChildren == 0) { | |
// | |
// Close the bus driver | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiCallerIdGuid, | |
(VOID **) &ParentDevicePath, | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
if (!EFI_ERROR (Status)) { | |
// | |
// Remove Parent Device Path from | |
// the Console Device Environment Variables | |
// | |
TerminalRemoveConsoleDevVariable ((CHAR16 *)VarConsoleInpDev, ParentDevicePath); | |
TerminalRemoveConsoleDevVariable ((CHAR16 *)VarConsoleOutDev, ParentDevicePath); | |
TerminalRemoveConsoleDevVariable ((CHAR16 *)VarErrorOutDev, ParentDevicePath); | |
// | |
// Uninstall the Terminal Driver's GUID Tag from the Serial controller | |
// | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
Controller, | |
&gEfiCallerIdGuid, | |
ParentDevicePath, | |
NULL | |
); | |
// | |
// Free the ParentDevicePath that was duplicated in Start() | |
// | |
if (!EFI_ERROR (Status)) { | |
gBS->FreePool (ParentDevicePath); | |
} | |
} | |
gBS->CloseProtocol ( | |
Controller, | |
&gEfiSerialIoProtocolGuid, | |
This->DriverBindingHandle, | |
Controller | |
); | |
gBS->CloseProtocol ( | |
Controller, | |
&gEfiDevicePathProtocolGuid, | |
This->DriverBindingHandle, | |
Controller | |
); | |
return EFI_SUCCESS; | |
} | |
AllChildrenStopped = TRUE; | |
for (Index = 0; Index < NumberOfChildren; Index++) { | |
Status = gBS->OpenProtocol ( | |
ChildHandleBuffer[Index], | |
&gEfiSimpleTextOutProtocolGuid, | |
(VOID **) &SimpleTextOutput, | |
This->DriverBindingHandle, | |
ChildHandleBuffer[Index], | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
if (!EFI_ERROR (Status)) { | |
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput); | |
gBS->CloseProtocol ( | |
Controller, | |
&gEfiSerialIoProtocolGuid, | |
This->DriverBindingHandle, | |
ChildHandleBuffer[Index] | |
); | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
ChildHandleBuffer[Index], | |
&gEfiSimpleTextInProtocolGuid, | |
&TerminalDevice->SimpleInput, | |
&gEfiSimpleTextOutProtocolGuid, | |
&TerminalDevice->SimpleTextOutput, | |
&gEfiDevicePathProtocolGuid, | |
TerminalDevice->DevicePath, | |
NULL | |
); | |
if (EFI_ERROR (Status)) { | |
gBS->OpenProtocol ( | |
Controller, | |
&gEfiSerialIoProtocolGuid, | |
(VOID **) &SerialIo, | |
This->DriverBindingHandle, | |
ChildHandleBuffer[Index], | |
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
); | |
} else { | |
if (TerminalDevice->ControllerNameTable != NULL) { | |
FreeUnicodeStringTable (TerminalDevice->ControllerNameTable); | |
} | |
Status = gBS->OpenProtocol ( | |
ChildHandleBuffer[Index], | |
&gEfiHotPlugDeviceGuid, | |
NULL, | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_TEST_PROTOCOL | |
); | |
if (!EFI_ERROR (Status)) { | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
ChildHandleBuffer[Index], | |
&gEfiHotPlugDeviceGuid, | |
NULL, | |
NULL | |
); | |
} else { | |
Status = EFI_SUCCESS; | |
} | |
gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut); | |
gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey); | |
gBS->FreePool (TerminalDevice->DevicePath); | |
gBS->FreePool (TerminalDevice); | |
} | |
} | |
if (EFI_ERROR (Status)) { | |
AllChildrenStopped = FALSE; | |
} | |
} | |
if (!AllChildrenStopped) { | |
return EFI_DEVICE_ERROR; | |
} | |
return EFI_SUCCESS; | |
} | |
VOID | |
TerminalUpdateConsoleDevVariable ( | |
IN CHAR16 *VariableName, | |
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN VariableSize; | |
UINT8 TerminalType; | |
EFI_DEVICE_PATH_PROTOCOL *Variable; | |
EFI_DEVICE_PATH_PROTOCOL *NewVariable; | |
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; | |
Variable = NULL; | |
// | |
// Get global variable and its size according to the name given. | |
// | |
Variable = TerminalGetVariableAndSize ( | |
VariableName, | |
&gEfiGlobalVariableGuid, | |
&VariableSize | |
); | |
// | |
// Append terminal device path onto the variable. | |
// | |
for (TerminalType = PcAnsiType; TerminalType <= VTUTF8Type; TerminalType++) { | |
SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath); | |
NewVariable = AppendDevicePathInstance (Variable, TempDevicePath); | |
if (Variable != NULL) { | |
gBS->FreePool (Variable); | |
} | |
if (TempDevicePath != NULL) { | |
gBS->FreePool (TempDevicePath); | |
} | |
Variable = NewVariable; | |
} | |
VariableSize = GetDevicePathSize (Variable); | |
Status = gRT->SetVariable ( | |
VariableName, | |
&gEfiGlobalVariableGuid, | |
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, | |
VariableSize, | |
Variable | |
); | |
gBS->FreePool (Variable); | |
return ; | |
} | |
VOID | |
TerminalRemoveConsoleDevVariable ( | |
IN CHAR16 *VariableName, | |
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath | |
) | |
/*++ | |
Routine Description: | |
Remove console device variable. | |
Arguments: | |
VariableName - A pointer to the variable name. | |
ParentDevicePath - A pointer to the parent device path. | |
Returns: | |
--*/ | |
{ | |
EFI_STATUS Status; | |
BOOLEAN FoundOne; | |
BOOLEAN Match; | |
UINTN VariableSize; | |
UINTN InstanceSize; | |
UINT8 TerminalType; | |
EFI_DEVICE_PATH_PROTOCOL *Instance; | |
EFI_DEVICE_PATH_PROTOCOL *Variable; | |
EFI_DEVICE_PATH_PROTOCOL *OriginalVariable; | |
EFI_DEVICE_PATH_PROTOCOL *NewVariable; | |
EFI_DEVICE_PATH_PROTOCOL *SavedNewVariable; | |
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; | |
Variable = NULL; | |
Instance = NULL; | |
// | |
// Get global variable and its size according to the name given. | |
// | |
Variable = TerminalGetVariableAndSize ( | |
VariableName, | |
&gEfiGlobalVariableGuid, | |
&VariableSize | |
); | |
if (Variable == NULL) { | |
return ; | |
} | |
FoundOne = FALSE; | |
OriginalVariable = Variable; | |
NewVariable = NULL; | |
// | |
// Get first device path instance from Variable | |
// | |
Instance = GetNextDevicePathInstance (&Variable, &InstanceSize); | |
if (Instance == NULL) { | |
gBS->FreePool (OriginalVariable); | |
return ; | |
} | |
// | |
// Loop through all the device path instances of Variable | |
// | |
do { | |
// | |
// Loop through all the terminal types that this driver supports | |
// | |
Match = FALSE; | |
for (TerminalType = PcAnsiType; TerminalType <= VTUTF8Type; TerminalType++) { | |
SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath); | |
// | |
// Compare the genterated device path to the current device path instance | |
// | |
if (TempDevicePath != NULL) { | |
if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) { | |
Match = TRUE; | |
FoundOne = TRUE; | |
} | |
gBS->FreePool (TempDevicePath); | |
} | |
} | |
// | |
// If a match was not found, then keep the current device path instance | |
// | |
if (!Match) { | |
SavedNewVariable = NewVariable; | |
NewVariable = AppendDevicePathInstance (NewVariable, Instance); | |
if (SavedNewVariable != NULL) { | |
gBS->FreePool (SavedNewVariable); | |
} | |
} | |
// | |
// Get next device path instance from Variable | |
// | |
gBS->FreePool (Instance); | |
Instance = GetNextDevicePathInstance (&Variable, &InstanceSize); | |
} while (Instance != NULL); | |
gBS->FreePool (OriginalVariable); | |
if (FoundOne) { | |
VariableSize = GetDevicePathSize (NewVariable); | |
Status = gRT->SetVariable ( | |
VariableName, | |
&gEfiGlobalVariableGuid, | |
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, | |
VariableSize, | |
NewVariable | |
); | |
} | |
if (NewVariable != NULL) { | |
gBS->FreePool (NewVariable); | |
} | |
return ; | |
} | |
VOID * | |
TerminalGetVariableAndSize ( | |
IN CHAR16 *Name, | |
IN EFI_GUID *VendorGuid, | |
OUT UINTN *VariableSize | |
) | |
/*++ | |
Routine Description: | |
Read the EFI variable (VendorGuid/Name) and return a dynamically allocated | |
buffer, and the size of the buffer. On failure return NULL. | |
Arguments: | |
Name - String part of EFI variable name | |
VendorGuid - GUID part of EFI variable name | |
VariableSize - Returns the size of the EFI variable that was read | |
Returns: | |
Dynamically allocated memory that contains a copy of the EFI variable. | |
Caller is repsoncible freeing the buffer. | |
NULL - Variable was not read | |
--*/ | |
{ | |
EFI_STATUS Status; | |
UINTN BufferSize; | |
VOID *Buffer; | |
Buffer = NULL; | |
// | |
// Pass in a small size buffer to find the actual variable size. | |
// | |
BufferSize = 1; | |
Buffer = AllocatePool (BufferSize); | |
if (Buffer == NULL) { | |
*VariableSize = 0; | |
return NULL; | |
} | |
Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer); | |
if (Status == EFI_SUCCESS) { | |
*VariableSize = BufferSize; | |
return Buffer; | |
} else if (Status == EFI_BUFFER_TOO_SMALL) { | |
// | |
// Allocate the buffer to return | |
// | |
gBS->FreePool (Buffer); | |
Buffer = AllocatePool (BufferSize); | |
if (Buffer == NULL) { | |
*VariableSize = 0; | |
return NULL; | |
} | |
// | |
// Read variable into the allocated buffer. | |
// | |
Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer); | |
if (EFI_ERROR (Status)) { | |
BufferSize = 0; | |
gBS->FreePool (Buffer); | |
Buffer = NULL; | |
} | |
} else { | |
// | |
// Variable not found or other errors met. | |
// | |
BufferSize = 0; | |
gBS->FreePool (Buffer); | |
Buffer = NULL; | |
} | |
*VariableSize = BufferSize; | |
return Buffer; | |
} | |
EFI_STATUS | |
SetTerminalDevicePath ( | |
IN UINT8 TerminalType, | |
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, | |
OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath | |
) | |
{ | |
VENDOR_DEVICE_PATH Node; | |
*TerminalDevicePath = NULL; | |
Node.Header.Type = MESSAGING_DEVICE_PATH; | |
Node.Header.SubType = MSG_VENDOR_DP; | |
// | |
// generate terminal device path node according to terminal type. | |
// | |
switch (TerminalType) { | |
case PcAnsiType: | |
CopyMem ( | |
&Node.Guid, | |
&gEfiPcAnsiGuid, | |
sizeof (EFI_GUID) | |
); | |
break; | |
case VT100Type: | |
CopyMem ( | |
&Node.Guid, | |
&gEfiVT100Guid, | |
sizeof (EFI_GUID) | |
); | |
break; | |
case VT100PlusType: | |
CopyMem ( | |
&Node.Guid, | |
&gEfiVT100PlusGuid, | |
sizeof (EFI_GUID) | |
); | |
break; | |
case VTUTF8Type: | |
CopyMem ( | |
&Node.Guid, | |
&gEfiVTUTF8Guid, | |
sizeof (EFI_GUID) | |
); | |
break; | |
default: | |
return EFI_UNSUPPORTED; | |
break; | |
} | |
SetDevicePathNodeLength ( | |
&Node.Header, | |
sizeof (VENDOR_DEVICE_PATH) | |
); | |
// | |
// append the terminal node onto parent device path | |
// to generate a complete terminal device path. | |
// | |
*TerminalDevicePath = AppendDevicePathNode ( | |
ParentDevicePath, | |
(EFI_DEVICE_PATH_PROTOCOL *) &Node | |
); | |
if (*TerminalDevicePath == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
return EFI_SUCCESS; | |
} | |
VOID | |
InitializeRawFiFo ( | |
IN TERMINAL_DEV *TerminalDevice | |
) | |
{ | |
// | |
// Make the raw fifo empty. | |
// | |
TerminalDevice->RawFiFo.Head = TerminalDevice->RawFiFo.Tail; | |
} | |
VOID | |
InitializeUnicodeFiFo ( | |
IN TERMINAL_DEV *TerminalDevice | |
) | |
{ | |
// | |
// Make the unicode fifo empty | |
// | |
TerminalDevice->UnicodeFiFo.Head = TerminalDevice->UnicodeFiFo.Tail; | |
} | |
VOID | |
InitializeEfiKeyFiFo ( | |
IN TERMINAL_DEV *TerminalDevice | |
) | |
{ | |
// | |
// Make the efi key fifo empty | |
// | |
TerminalDevice->EfiKeyFiFo.Head = TerminalDevice->EfiKeyFiFo.Tail; | |
} |