mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-27 16:58:09 +01:00
1375 lines
42 KiB
C
1375 lines
42 KiB
C
|
/** @file
|
||
|
Produces Simple Text Input Protocol, Simple Text Input Extended Protocol and
|
||
|
Simple Text Output Protocol upon Serial IO Protocol.
|
||
|
|
||
|
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||
|
|
||
|
**/
|
||
|
|
||
|
|
||
|
#include "Terminal.h"
|
||
|
|
||
|
//
|
||
|
// Globals
|
||
|
//
|
||
|
EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = {
|
||
|
TerminalDriverBindingSupported,
|
||
|
TerminalDriverBindingStart,
|
||
|
TerminalDriverBindingStop,
|
||
|
0xa,
|
||
|
NULL,
|
||
|
NULL
|
||
|
};
|
||
|
|
||
|
|
||
|
EFI_GUID *mTerminalType[] = {
|
||
|
&gEfiPcAnsiGuid,
|
||
|
&gEfiVT100Guid,
|
||
|
&gEfiVT100PlusGuid,
|
||
|
&gEfiVTUTF8Guid,
|
||
|
&gEfiTtyTermGuid
|
||
|
};
|
||
|
|
||
|
|
||
|
CHAR16 *mSerialConsoleNames[] = {
|
||
|
L"PC-ANSI Serial Console",
|
||
|
L"VT-100 Serial Console",
|
||
|
L"VT-100+ Serial Console",
|
||
|
L"VT-UTF8 Serial Console",
|
||
|
L"Tty Terminal Serial Console"
|
||
|
};
|
||
|
|
||
|
TERMINAL_DEV mTerminalDevTemplate = {
|
||
|
TERMINAL_DEV_SIGNATURE,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
{ // SimpleTextInput
|
||
|
TerminalConInReset,
|
||
|
TerminalConInReadKeyStroke,
|
||
|
NULL
|
||
|
},
|
||
|
{ // SimpleTextOutput
|
||
|
TerminalConOutReset,
|
||
|
TerminalConOutOutputString,
|
||
|
TerminalConOutTestString,
|
||
|
TerminalConOutQueryMode,
|
||
|
TerminalConOutSetMode,
|
||
|
TerminalConOutSetAttribute,
|
||
|
TerminalConOutClearScreen,
|
||
|
TerminalConOutSetCursorPosition,
|
||
|
TerminalConOutEnableCursor,
|
||
|
NULL
|
||
|
},
|
||
|
{ // SimpleTextOutputMode
|
||
|
1, // MaxMode
|
||
|
0, // Mode
|
||
|
EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK), // Attribute
|
||
|
0, // CursorColumn
|
||
|
0, // CursorRow
|
||
|
TRUE // CursorVisible
|
||
|
},
|
||
|
NULL, // TerminalConsoleModeData
|
||
|
0, // SerialInTimeOut
|
||
|
|
||
|
NULL, // RawFifo
|
||
|
NULL, // UnicodeFiFo
|
||
|
NULL, // EfiKeyFiFo
|
||
|
NULL, // EfiKeyFiFoForNotify
|
||
|
|
||
|
NULL, // ControllerNameTable
|
||
|
NULL, // TimerEvent
|
||
|
NULL, // TwoSecondTimeOut
|
||
|
INPUT_STATE_DEFAULT,
|
||
|
RESET_STATE_DEFAULT,
|
||
|
{
|
||
|
0,
|
||
|
0,
|
||
|
0
|
||
|
},
|
||
|
0,
|
||
|
FALSE,
|
||
|
{ // SimpleTextInputEx
|
||
|
TerminalConInResetEx,
|
||
|
TerminalConInReadKeyStrokeEx,
|
||
|
NULL,
|
||
|
TerminalConInSetState,
|
||
|
TerminalConInRegisterKeyNotify,
|
||
|
TerminalConInUnregisterKeyNotify,
|
||
|
},
|
||
|
{ // NotifyList
|
||
|
NULL,
|
||
|
NULL,
|
||
|
},
|
||
|
NULL // KeyNotifyProcessEvent
|
||
|
};
|
||
|
|
||
|
TERMINAL_CONSOLE_MODE_DATA mTerminalConsoleModeData[] = {
|
||
|
{80, 25},
|
||
|
{80, 50},
|
||
|
{100, 31},
|
||
|
//
|
||
|
// New modes can be added here.
|
||
|
//
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
Convert the GUID representation of terminal type to enum type.
|
||
|
|
||
|
@param Guid The GUID representation of terminal type.
|
||
|
|
||
|
@return The terminal type in enum type.
|
||
|
**/
|
||
|
TERMINAL_TYPE
|
||
|
TerminalTypeFromGuid (
|
||
|
IN EFI_GUID *Guid
|
||
|
)
|
||
|
{
|
||
|
TERMINAL_TYPE Type;
|
||
|
|
||
|
for (Type = 0; Type < ARRAY_SIZE (mTerminalType); Type++) {
|
||
|
if (CompareGuid (Guid, mTerminalType[Type])) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return Type;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Test to see if this driver supports Controller.
|
||
|
|
||
|
@param This Protocol instance pointer.
|
||
|
@param Controller 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_ALREADY_STARTED This driver is already running on this device.
|
||
|
@retval other This driver does not support this device.
|
||
|
|
||
|
**/
|
||
|
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) {
|
||
|
//
|
||
|
// Check if RemainingDevicePath is the End of Device Path Node,
|
||
|
// if yes, go on checking other conditions
|
||
|
//
|
||
|
if (!IsDevicePathEnd (RemainingDevicePath)) {
|
||
|
//
|
||
|
// If RemainingDevicePath isn't the End of Device Path Node,
|
||
|
// check its validation
|
||
|
//
|
||
|
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+, VT-UTF8, and TtyTerm terminal types
|
||
|
//
|
||
|
if (TerminalTypeFromGuid (&Node->Guid) == ARRAY_SIZE (mTerminalType)) {
|
||
|
return EFI_UNSUPPORTED;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// Open the IO Abstraction(s) needed to perform the supported test
|
||
|
// 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
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Open the EFI Device Path protocol 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;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Close protocol, don't use device path protocol in the Support() function
|
||
|
//
|
||
|
gBS->CloseProtocol (
|
||
|
Controller,
|
||
|
&gEfiDevicePathProtocolGuid,
|
||
|
This->DriverBindingHandle,
|
||
|
Controller
|
||
|
);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
Free notify functions list.
|
||
|
|
||
|
@param ListHead The list head
|
||
|
|
||
|
@retval EFI_SUCCESS Free the notify list successfully.
|
||
|
@retval EFI_INVALID_PARAMETER ListHead is NULL.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
TerminalFreeNotifyList (
|
||
|
IN OUT LIST_ENTRY *ListHead
|
||
|
)
|
||
|
{
|
||
|
TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode;
|
||
|
|
||
|
if (ListHead == NULL) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
while (!IsListEmpty (ListHead)) {
|
||
|
NotifyNode = CR (
|
||
|
ListHead->ForwardLink,
|
||
|
TERMINAL_CONSOLE_IN_EX_NOTIFY,
|
||
|
NotifyEntry,
|
||
|
TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
|
||
|
);
|
||
|
RemoveEntryList (ListHead->ForwardLink);
|
||
|
FreePool (NotifyNode);
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Initialize all the text modes which the terminal console supports.
|
||
|
|
||
|
It returns information for available text modes that the terminal can support.
|
||
|
|
||
|
@param[out] TextModeCount The total number of text modes that terminal console supports.
|
||
|
|
||
|
@return The buffer to the text modes column and row information.
|
||
|
Caller is responsible to free it when it's non-NULL.
|
||
|
|
||
|
**/
|
||
|
TERMINAL_CONSOLE_MODE_DATA *
|
||
|
InitializeTerminalConsoleTextMode (
|
||
|
OUT INT32 *TextModeCount
|
||
|
)
|
||
|
{
|
||
|
TERMINAL_CONSOLE_MODE_DATA *TextModeData;
|
||
|
|
||
|
ASSERT (TextModeCount != NULL);
|
||
|
|
||
|
TextModeData = AllocateCopyPool (sizeof (mTerminalConsoleModeData), mTerminalConsoleModeData);
|
||
|
if (TextModeData == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
*TextModeCount = ARRAY_SIZE (mTerminalConsoleModeData);
|
||
|
|
||
|
DEBUG_CODE (
|
||
|
INT32 Index;
|
||
|
for (Index = 0; Index < *TextModeCount; Index++) {
|
||
|
DEBUG ((DEBUG_INFO, "Terminal - Mode %d, Column = %d, Row = %d\n",
|
||
|
Index, TextModeData[Index].Columns, TextModeData[Index].Rows));
|
||
|
}
|
||
|
);
|
||
|
return TextModeData;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Stop the terminal state machine.
|
||
|
|
||
|
@param TerminalDevice The terminal device.
|
||
|
**/
|
||
|
VOID
|
||
|
StopTerminalStateMachine (
|
||
|
TERMINAL_DEV *TerminalDevice
|
||
|
)
|
||
|
{
|
||
|
EFI_TPL OriginalTpl;
|
||
|
|
||
|
OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);
|
||
|
|
||
|
gBS->CloseEvent (TerminalDevice->TimerEvent);
|
||
|
gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
|
||
|
|
||
|
gBS->RestoreTPL (OriginalTpl);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Start the terminal state machine.
|
||
|
|
||
|
@param TerminalDevice The terminal device.
|
||
|
**/
|
||
|
VOID
|
||
|
StartTerminalStateMachine (
|
||
|
TERMINAL_DEV *TerminalDevice
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
Status = gBS->CreateEvent (
|
||
|
EVT_TIMER | EVT_NOTIFY_SIGNAL,
|
||
|
TPL_NOTIFY,
|
||
|
TerminalConInTimerHandler,
|
||
|
TerminalDevice,
|
||
|
&TerminalDevice->TimerEvent
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
|
||
|
Status = gBS->SetTimer (
|
||
|
TerminalDevice->TimerEvent,
|
||
|
TimerPeriodic,
|
||
|
KEYBOARD_TIMER_INTERVAL
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
|
||
|
Status = gBS->CreateEvent (
|
||
|
EVT_TIMER,
|
||
|
TPL_CALLBACK,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
&TerminalDevice->TwoSecondTimeOut
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Initialize the controller name table.
|
||
|
|
||
|
@param TerminalType The terminal type.
|
||
|
@param ControllerNameTable The controller name table.
|
||
|
|
||
|
@retval EFI_SUCCESS The controller name table is initialized successfully.
|
||
|
@retval others Return status of AddUnicodeString2 ().
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
InitializeControllerNameTable (
|
||
|
TERMINAL_TYPE TerminalType,
|
||
|
EFI_UNICODE_STRING_TABLE **ControllerNameTable
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
EFI_UNICODE_STRING_TABLE *Table;
|
||
|
|
||
|
ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));
|
||
|
Table = NULL;
|
||
|
Status = AddUnicodeString2 (
|
||
|
"eng",
|
||
|
gTerminalComponentName.SupportedLanguages,
|
||
|
&Table,
|
||
|
mSerialConsoleNames[TerminalType],
|
||
|
TRUE
|
||
|
);
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
Status = AddUnicodeString2 (
|
||
|
"en",
|
||
|
gTerminalComponentName2.SupportedLanguages,
|
||
|
&Table,
|
||
|
mSerialConsoleNames[TerminalType],
|
||
|
FALSE
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
FreeUnicodeStringTable (Table);
|
||
|
}
|
||
|
}
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
*ControllerNameTable = Table;
|
||
|
}
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Start this driver on Controller by opening a Serial IO protocol,
|
||
|
reading Device Path, and creating a child handle with a Simple Text In,
|
||
|
Simple Text In Ex and Simple Text Out protocol, and device path protocol.
|
||
|
And store Console Device Environment Variables.
|
||
|
|
||
|
@param This Protocol instance pointer.
|
||
|
@param Controller 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 Controller.
|
||
|
@retval EFI_ALREADY_STARTED This driver is already running on Controller.
|
||
|
@retval other This driver does not support this device.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
TerminalDriverBindingStart (
|
||
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||
|
IN EFI_HANDLE Controller,
|
||
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
EFI_SERIAL_IO_PROTOCOL *SerialIo;
|
||
|
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
|
||
|
EFI_DEVICE_PATH_PROTOCOL *Vendor;
|
||
|
EFI_HANDLE SerialIoHandle;
|
||
|
EFI_SERIAL_IO_MODE *Mode;
|
||
|
UINTN SerialInTimeOut;
|
||
|
TERMINAL_DEV *TerminalDevice;
|
||
|
UINT8 TerminalType;
|
||
|
EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
|
||
|
UINTN EntryCount;
|
||
|
UINTN Index;
|
||
|
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
|
||
|
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextInput;
|
||
|
EFI_UNICODE_STRING_TABLE *ControllerNameTable;
|
||
|
|
||
|
//
|
||
|
// 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
|
||
|
);
|
||
|
ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_ALREADY_STARTED));
|
||
|
if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// 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
|
||
|
);
|
||
|
ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_ALREADY_STARTED));
|
||
|
if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
if (!IsHotPlugDevice (ParentDevicePath)) {
|
||
|
//
|
||
|
// if the serial device is a hot plug device, do not update the
|
||
|
// ConInDev, ConOutDev, and StdErrDev variables.
|
||
|
//
|
||
|
TerminalUpdateConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);
|
||
|
TerminalUpdateConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
|
||
|
TerminalUpdateConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Do not create any child for END remaining device path.
|
||
|
//
|
||
|
if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
if (Status == EFI_ALREADY_STARTED) {
|
||
|
|
||
|
if (RemainingDevicePath == NULL) {
|
||
|
//
|
||
|
// If RemainingDevicePath is NULL or is the End of Device Path Node
|
||
|
//
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This driver can only produce one child per serial port.
|
||
|
// Change its terminal type as remaining device path requests.
|
||
|
//
|
||
|
Status = gBS->OpenProtocolInformation (
|
||
|
Controller,
|
||
|
&gEfiSerialIoProtocolGuid,
|
||
|
&OpenInfoBuffer,
|
||
|
&EntryCount
|
||
|
);
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
Status = EFI_NOT_FOUND;
|
||
|
for (Index = 0; Index < EntryCount; Index++) {
|
||
|
if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
|
||
|
Status = gBS->OpenProtocol (
|
||
|
OpenInfoBuffer[Index].ControllerHandle,
|
||
|
&gEfiSimpleTextInProtocolGuid,
|
||
|
(VOID **) &SimpleTextInput,
|
||
|
This->DriverBindingHandle,
|
||
|
Controller,
|
||
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||
|
);
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput);
|
||
|
TerminalType = TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH *) RemainingDevicePath)->Guid);
|
||
|
ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));
|
||
|
if (TerminalDevice->TerminalType != TerminalType) {
|
||
|
Status = InitializeControllerNameTable (TerminalType, &ControllerNameTable);
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
StopTerminalStateMachine (TerminalDevice);
|
||
|
//
|
||
|
// Update the device path
|
||
|
//
|
||
|
Vendor = TerminalDevice->DevicePath;
|
||
|
Status = gBS->LocateDevicePath (&gEfiSerialIoProtocolGuid, &Vendor, &SerialIoHandle);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
CopyGuid (&((VENDOR_DEVICE_PATH *) Vendor)->Guid, mTerminalType[TerminalType]);
|
||
|
Status = gBS->ReinstallProtocolInterface (
|
||
|
TerminalDevice->Handle,
|
||
|
&gEfiDevicePathProtocolGuid,
|
||
|
TerminalDevice->DevicePath,
|
||
|
TerminalDevice->DevicePath
|
||
|
);
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
TerminalDevice->TerminalType = TerminalType;
|
||
|
StartTerminalStateMachine (TerminalDevice);
|
||
|
FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
|
||
|
TerminalDevice->ControllerNameTable = ControllerNameTable;
|
||
|
} else {
|
||
|
//
|
||
|
// Restore the device path on failure
|
||
|
//
|
||
|
CopyGuid (&((VENDOR_DEVICE_PATH *) Vendor)->Guid, mTerminalType[TerminalDevice->TerminalType]);
|
||
|
FreeUnicodeStringTable (ControllerNameTable);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
FreePool (OpenInfoBuffer);
|
||
|
}
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Initialize the Terminal Dev
|
||
|
//
|
||
|
TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);
|
||
|
if (TerminalDevice == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
goto CloseProtocols;
|
||
|
}
|
||
|
|
||
|
if (RemainingDevicePath == NULL) {
|
||
|
//
|
||
|
// If RemainingDevicePath is NULL, use default terminal type
|
||
|
//
|
||
|
TerminalDevice->TerminalType = PcdGet8 (PcdDefaultTerminalType);
|
||
|
} else {
|
||
|
//
|
||
|
// End of Device Path Node is handled in above.
|
||
|
//
|
||
|
ASSERT (!IsDevicePathEnd (RemainingDevicePath));
|
||
|
//
|
||
|
// If RemainingDevicePath isn't the End of Device Path Node,
|
||
|
// Use the RemainingDevicePath to determine the terminal type
|
||
|
//
|
||
|
TerminalDevice->TerminalType = TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH *) RemainingDevicePath)->Guid);
|
||
|
}
|
||
|
ASSERT (TerminalDevice->TerminalType < ARRAY_SIZE (mTerminalType));
|
||
|
TerminalDevice->SerialIo = SerialIo;
|
||
|
|
||
|
//
|
||
|
// Build the component name for the child device
|
||
|
//
|
||
|
Status = InitializeControllerNameTable (TerminalDevice->TerminalType, &TerminalDevice->ControllerNameTable);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto FreeResources;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Build the device path for the child device
|
||
|
//
|
||
|
Status = SetTerminalDevicePath (TerminalDevice->TerminalType, ParentDevicePath, &TerminalDevice->DevicePath);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto FreeResources;
|
||
|
}
|
||
|
|
||
|
InitializeListHead (&TerminalDevice->NotifyList);
|
||
|
Status = gBS->CreateEvent (
|
||
|
EVT_NOTIFY_WAIT,
|
||
|
TPL_NOTIFY,
|
||
|
TerminalConInWaitForKeyEx,
|
||
|
TerminalDevice,
|
||
|
&TerminalDevice->SimpleInputEx.WaitForKeyEx
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
|
||
|
Status = gBS->CreateEvent (
|
||
|
EVT_NOTIFY_WAIT,
|
||
|
TPL_NOTIFY,
|
||
|
TerminalConInWaitForKey,
|
||
|
TerminalDevice,
|
||
|
&TerminalDevice->SimpleInput.WaitForKey
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
Status = gBS->CreateEvent (
|
||
|
EVT_NOTIFY_SIGNAL,
|
||
|
TPL_CALLBACK,
|
||
|
KeyNotifyProcessHandler,
|
||
|
TerminalDevice,
|
||
|
&TerminalDevice->KeyNotifyProcessEvent
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
|
||
|
//
|
||
|
// Allocates and initializes the FIFO buffer to be zero, used for accommodating
|
||
|
// the pre-read pending characters.
|
||
|
//
|
||
|
TerminalDevice->RawFiFo = AllocateZeroPool (sizeof (RAW_DATA_FIFO));
|
||
|
if (TerminalDevice->RawFiFo == NULL) {
|
||
|
goto FreeResources;
|
||
|
}
|
||
|
TerminalDevice->UnicodeFiFo = AllocateZeroPool (sizeof (UNICODE_FIFO));
|
||
|
if (TerminalDevice->UnicodeFiFo == NULL) {
|
||
|
goto FreeResources;
|
||
|
}
|
||
|
TerminalDevice->EfiKeyFiFo = AllocateZeroPool (sizeof (EFI_KEY_FIFO));
|
||
|
if (TerminalDevice->EfiKeyFiFo == NULL) {
|
||
|
goto FreeResources;
|
||
|
}
|
||
|
TerminalDevice->EfiKeyFiFoForNotify = AllocateZeroPool (sizeof (EFI_KEY_FIFO));
|
||
|
if (TerminalDevice->EfiKeyFiFoForNotify == NULL) {
|
||
|
goto FreeResources;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// 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,
|
||
|
(EFI_PARITY_TYPE) (Mode->Parity),
|
||
|
(UINT8) Mode->DataBits,
|
||
|
(EFI_STOP_BITS_TYPE) (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;
|
||
|
}
|
||
|
|
||
|
SimpleTextOutput = &TerminalDevice->SimpleTextOutput;
|
||
|
SimpleTextInput = &TerminalDevice->SimpleInput;
|
||
|
|
||
|
//
|
||
|
// Initialize SimpleTextOut instance
|
||
|
//
|
||
|
SimpleTextOutput->Mode = &TerminalDevice->SimpleTextOutputMode;
|
||
|
TerminalDevice->TerminalConsoleModeData = InitializeTerminalConsoleTextMode (
|
||
|
&SimpleTextOutput->Mode->MaxMode
|
||
|
);
|
||
|
if (TerminalDevice->TerminalConsoleModeData == NULL) {
|
||
|
goto FreeResources;
|
||
|
}
|
||
|
//
|
||
|
// For terminal devices, cursor is always visible
|
||
|
//
|
||
|
SimpleTextOutput->Mode->CursorVisible = TRUE;
|
||
|
Status = SimpleTextOutput->SetAttribute (SimpleTextOutput, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
Status = SimpleTextOutput->Reset (SimpleTextOutput, FALSE);
|
||
|
}
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto ReportError;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Initialize SimpleTextInput instance
|
||
|
//
|
||
|
Status = SimpleTextInput->Reset (SimpleTextInput, FALSE);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto ReportError;
|
||
|
}
|
||
|
|
||
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
||
|
&TerminalDevice->Handle,
|
||
|
&gEfiSimpleTextInProtocolGuid, &TerminalDevice->SimpleInput,
|
||
|
&gEfiSimpleTextInputExProtocolGuid, &TerminalDevice->SimpleInputEx,
|
||
|
&gEfiSimpleTextOutProtocolGuid, &TerminalDevice->SimpleTextOutput,
|
||
|
&gEfiDevicePathProtocolGuid, TerminalDevice->DevicePath,
|
||
|
NULL
|
||
|
);
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
Status = gBS->OpenProtocol (
|
||
|
Controller,
|
||
|
&gEfiSerialIoProtocolGuid,
|
||
|
(VOID **) &TerminalDevice->SerialIo,
|
||
|
This->DriverBindingHandle,
|
||
|
TerminalDevice->Handle,
|
||
|
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
StartTerminalStateMachine (TerminalDevice);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
ReportError:
|
||
|
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
|
||
|
EFI_ERROR_CODE | EFI_ERROR_MINOR,
|
||
|
(EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
|
||
|
ParentDevicePath
|
||
|
);
|
||
|
|
||
|
FreeResources:
|
||
|
ASSERT (TerminalDevice != NULL);
|
||
|
|
||
|
if (TerminalDevice->SimpleInput.WaitForKey != NULL) {
|
||
|
gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
|
||
|
}
|
||
|
if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) {
|
||
|
gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
|
||
|
}
|
||
|
if (TerminalDevice->KeyNotifyProcessEvent != NULL) {
|
||
|
gBS->CloseEvent (TerminalDevice->KeyNotifyProcessEvent);
|
||
|
}
|
||
|
|
||
|
if (TerminalDevice->RawFiFo != NULL) {
|
||
|
FreePool (TerminalDevice->RawFiFo);
|
||
|
}
|
||
|
if (TerminalDevice->UnicodeFiFo != NULL) {
|
||
|
FreePool (TerminalDevice->UnicodeFiFo);
|
||
|
}
|
||
|
if (TerminalDevice->EfiKeyFiFo != NULL) {
|
||
|
FreePool (TerminalDevice->EfiKeyFiFo);
|
||
|
}
|
||
|
if (TerminalDevice->EfiKeyFiFoForNotify != NULL) {
|
||
|
FreePool (TerminalDevice->EfiKeyFiFoForNotify);
|
||
|
}
|
||
|
|
||
|
if (TerminalDevice->ControllerNameTable != NULL) {
|
||
|
FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
|
||
|
}
|
||
|
|
||
|
if (TerminalDevice->DevicePath != NULL) {
|
||
|
FreePool (TerminalDevice->DevicePath);
|
||
|
}
|
||
|
|
||
|
if (TerminalDevice->TerminalConsoleModeData != NULL) {
|
||
|
FreePool (TerminalDevice->TerminalConsoleModeData);
|
||
|
}
|
||
|
|
||
|
FreePool (TerminalDevice);
|
||
|
|
||
|
CloseProtocols:
|
||
|
|
||
|
//
|
||
|
// Remove Parent Device Path from
|
||
|
// the Console Device Environment Variables
|
||
|
//
|
||
|
TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);
|
||
|
TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
|
||
|
TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
|
||
|
|
||
|
Status = gBS->CloseProtocol (
|
||
|
Controller,
|
||
|
&gEfiSerialIoProtocolGuid,
|
||
|
This->DriverBindingHandle,
|
||
|
Controller
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
|
||
|
Status = gBS->CloseProtocol (
|
||
|
Controller,
|
||
|
&gEfiDevicePathProtocolGuid,
|
||
|
This->DriverBindingHandle,
|
||
|
Controller
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Stop this driver on Controller by closing Simple Text In, Simple Text
|
||
|
In Ex, Simple Text Out protocol, and removing parent device path from
|
||
|
Console Device Environment Variables.
|
||
|
|
||
|
@param This Protocol instance pointer.
|
||
|
@param Controller 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 Controller.
|
||
|
@retval other This driver could not be removed from this device.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
TerminalDriverBindingStop (
|
||
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||
|
IN EFI_HANDLE Controller,
|
||
|
IN UINTN NumberOfChildren,
|
||
|
IN EFI_HANDLE *ChildHandleBuffer
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
UINTN Index;
|
||
|
BOOLEAN AllChildrenStopped;
|
||
|
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
|
||
|
TERMINAL_DEV *TerminalDevice;
|
||
|
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
|
||
|
EFI_SERIAL_IO_PROTOCOL *SerialIo;
|
||
|
|
||
|
//
|
||
|
// 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,
|
||
|
&gEfiDevicePathProtocolGuid,
|
||
|
(VOID **) &ParentDevicePath,
|
||
|
This->DriverBindingHandle,
|
||
|
Controller,
|
||
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
|
||
|
//
|
||
|
// Remove Parent Device Path from
|
||
|
// the Console Device Environment Variables
|
||
|
//
|
||
|
TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);
|
||
|
TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
|
||
|
TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, 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,
|
||
|
&gEfiSimpleTextInputExProtocolGuid,
|
||
|
&TerminalDevice->SimpleInputEx,
|
||
|
&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 {
|
||
|
|
||
|
FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
|
||
|
StopTerminalStateMachine (TerminalDevice);
|
||
|
gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
|
||
|
gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
|
||
|
gBS->CloseEvent (TerminalDevice->KeyNotifyProcessEvent);
|
||
|
TerminalFreeNotifyList (&TerminalDevice->NotifyList);
|
||
|
FreePool (TerminalDevice->DevicePath);
|
||
|
FreePool (TerminalDevice->TerminalConsoleModeData);
|
||
|
FreePool (TerminalDevice);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
AllChildrenStopped = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!AllChildrenStopped) {
|
||
|
return EFI_DEVICE_ERROR;
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Compare a device path data structure to that of all the nodes of a
|
||
|
second device path instance.
|
||
|
|
||
|
@param Multi A pointer to a multi-instance device path data structure.
|
||
|
@param Single A pointer to a single-instance device path data structure.
|
||
|
|
||
|
@retval TRUE If the Single is contained within Multi.
|
||
|
@retval FALSE The Single is not match within Multi.
|
||
|
|
||
|
**/
|
||
|
BOOLEAN
|
||
|
MatchDevicePaths (
|
||
|
IN EFI_DEVICE_PATH_PROTOCOL *Multi,
|
||
|
IN EFI_DEVICE_PATH_PROTOCOL *Single
|
||
|
)
|
||
|
{
|
||
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
||
|
EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
|
||
|
UINTN Size;
|
||
|
|
||
|
DevicePath = Multi;
|
||
|
DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
|
||
|
//
|
||
|
// Search for the match of 'Single' in 'Multi'
|
||
|
//
|
||
|
while (DevicePathInst != NULL) {
|
||
|
//
|
||
|
// If the single device path is found in multiple device paths,
|
||
|
// return success
|
||
|
//
|
||
|
if (CompareMem (Single, DevicePathInst, Size) == 0) {
|
||
|
FreePool (DevicePathInst);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
FreePool (DevicePathInst);
|
||
|
DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Update terminal device path in Console Device Environment Variables.
|
||
|
|
||
|
@param VariableName The Console Device Environment Variable.
|
||
|
@param ParentDevicePath The terminal device path to be updated.
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
TerminalUpdateConsoleDevVariable (
|
||
|
IN CHAR16 *VariableName,
|
||
|
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
UINTN NameSize;
|
||
|
UINTN VariableSize;
|
||
|
TERMINAL_TYPE TerminalType;
|
||
|
EFI_DEVICE_PATH_PROTOCOL *Variable;
|
||
|
EFI_DEVICE_PATH_PROTOCOL *NewVariable;
|
||
|
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
||
|
EDKII_SET_VARIABLE_STATUS *SetVariableStatus;
|
||
|
|
||
|
//
|
||
|
// Get global variable and its size according to the name given.
|
||
|
//
|
||
|
Status = GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
|
||
|
if (Status == EFI_NOT_FOUND) {
|
||
|
Status = EFI_SUCCESS;
|
||
|
Variable = NULL;
|
||
|
}
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Append terminal device path onto the variable.
|
||
|
//
|
||
|
for (TerminalType = 0; TerminalType < ARRAY_SIZE (mTerminalType); TerminalType++) {
|
||
|
SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
|
||
|
|
||
|
if (TempDevicePath != NULL) {
|
||
|
if (!MatchDevicePaths (Variable, TempDevicePath)) {
|
||
|
NewVariable = AppendDevicePathInstance (Variable, TempDevicePath);
|
||
|
if (NewVariable != NULL) {
|
||
|
if (Variable != NULL) {
|
||
|
FreePool (Variable);
|
||
|
}
|
||
|
Variable = NewVariable;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FreePool (TempDevicePath);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
VariableSize = GetDevicePathSize (Variable);
|
||
|
|
||
|
Status = gRT->SetVariable (
|
||
|
VariableName,
|
||
|
&gEfiGlobalVariableGuid,
|
||
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
||
|
VariableSize,
|
||
|
Variable
|
||
|
);
|
||
|
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
NameSize = StrSize (VariableName);
|
||
|
SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize);
|
||
|
if (SetVariableStatus != NULL) {
|
||
|
CopyGuid (&SetVariableStatus->Guid, &gEfiGlobalVariableGuid);
|
||
|
SetVariableStatus->NameSize = NameSize;
|
||
|
SetVariableStatus->DataSize = VariableSize;
|
||
|
SetVariableStatus->SetStatus = Status;
|
||
|
SetVariableStatus->Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
|
||
|
CopyMem (SetVariableStatus + 1, VariableName, NameSize);
|
||
|
CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Variable, VariableSize);
|
||
|
|
||
|
REPORT_STATUS_CODE_EX (
|
||
|
EFI_ERROR_CODE,
|
||
|
PcdGet32 (PcdErrorCodeSetVariable),
|
||
|
0,
|
||
|
NULL,
|
||
|
&gEdkiiStatusCodeDataTypeVariableGuid,
|
||
|
SetVariableStatus,
|
||
|
sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize
|
||
|
);
|
||
|
|
||
|
FreePool (SetVariableStatus);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FreePool (Variable);
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
Remove terminal device path from Console Device Environment Variables.
|
||
|
|
||
|
@param VariableName Console Device Environment Variables.
|
||
|
@param ParentDevicePath The terminal device path to be updated.
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
TerminalRemoveConsoleDevVariable (
|
||
|
IN CHAR16 *VariableName,
|
||
|
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
BOOLEAN FoundOne;
|
||
|
BOOLEAN Match;
|
||
|
UINTN VariableSize;
|
||
|
UINTN InstanceSize;
|
||
|
TERMINAL_TYPE 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;
|
||
|
|
||
|
Instance = NULL;
|
||
|
|
||
|
//
|
||
|
// Get global variable and its size according to the name given.
|
||
|
//
|
||
|
GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
|
||
|
if (Variable == NULL) {
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
FoundOne = FALSE;
|
||
|
OriginalVariable = Variable;
|
||
|
NewVariable = NULL;
|
||
|
|
||
|
//
|
||
|
// Get first device path instance from Variable
|
||
|
//
|
||
|
Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
|
||
|
if (Instance == NULL) {
|
||
|
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 = 0; TerminalType < ARRAY_SIZE (mTerminalType); TerminalType++) {
|
||
|
|
||
|
SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
|
||
|
|
||
|
//
|
||
|
// Compare the generated device path to the current device path instance
|
||
|
//
|
||
|
if (TempDevicePath != NULL) {
|
||
|
if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) {
|
||
|
Match = TRUE;
|
||
|
FoundOne = TRUE;
|
||
|
}
|
||
|
|
||
|
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) {
|
||
|
FreePool (SavedNewVariable);
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// Get next device path instance from Variable
|
||
|
//
|
||
|
FreePool (Instance);
|
||
|
Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
|
||
|
} while (Instance != NULL);
|
||
|
|
||
|
FreePool (OriginalVariable);
|
||
|
|
||
|
if (FoundOne) {
|
||
|
VariableSize = GetDevicePathSize (NewVariable);
|
||
|
|
||
|
Status = gRT->SetVariable (
|
||
|
VariableName,
|
||
|
&gEfiGlobalVariableGuid,
|
||
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
||
|
VariableSize,
|
||
|
NewVariable
|
||
|
);
|
||
|
//
|
||
|
// Shrinking variable with existing variable driver implementation shouldn't fail.
|
||
|
//
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
}
|
||
|
|
||
|
if (NewVariable != NULL) {
|
||
|
FreePool (NewVariable);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Build terminal device path according to terminal type.
|
||
|
|
||
|
@param TerminalType The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.
|
||
|
@param ParentDevicePath Parent device path.
|
||
|
@param TerminalDevicePath Returned terminal device path, if building successfully.
|
||
|
|
||
|
@retval EFI_UNSUPPORTED Terminal does not belong to the supported type.
|
||
|
@retval EFI_OUT_OF_RESOURCES Generate terminal device path failed.
|
||
|
@retval EFI_SUCCESS Build terminal device path successfully.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
SetTerminalDevicePath (
|
||
|
IN TERMINAL_TYPE TerminalType,
|
||
|
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
|
||
|
OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath
|
||
|
)
|
||
|
{
|
||
|
VENDOR_DEVICE_PATH Node;
|
||
|
|
||
|
ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));
|
||
|
Node.Header.Type = MESSAGING_DEVICE_PATH;
|
||
|
Node.Header.SubType = MSG_VENDOR_DP;
|
||
|
SetDevicePathNodeLength (&Node.Header, sizeof (VENDOR_DEVICE_PATH));
|
||
|
CopyGuid (&Node.Guid, mTerminalType[TerminalType]);
|
||
|
|
||
|
//
|
||
|
// 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;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
The user Entry Point for module Terminal. The user code starts with this function.
|
||
|
|
||
|
@param ImageHandle The firmware allocated handle for the EFI image.
|
||
|
@param SystemTable A pointer to the EFI System Table.
|
||
|
|
||
|
@retval EFI_SUCCESS The entry point is executed successfully.
|
||
|
@retval other Some error occurs when executing this entry point.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
InitializeTerminal(
|
||
|
IN EFI_HANDLE ImageHandle,
|
||
|
IN EFI_SYSTEM_TABLE *SystemTable
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
|
||
|
//
|
||
|
// Install driver model protocol(s).
|
||
|
//
|
||
|
Status = EfiLibInstallDriverBindingComponentName2 (
|
||
|
ImageHandle,
|
||
|
SystemTable,
|
||
|
&gTerminalDriverBinding,
|
||
|
ImageHandle,
|
||
|
&gTerminalComponentName,
|
||
|
&gTerminalComponentName2
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Check if the device supports hot-plug through its device path.
|
||
|
|
||
|
This function could be updated to check more types of Hot Plug devices.
|
||
|
Currently, it checks USB and PCCard device.
|
||
|
|
||
|
@param DevicePath Pointer to device's device path.
|
||
|
|
||
|
@retval TRUE The devcie is a hot-plug device
|
||
|
@retval FALSE The devcie is not a hot-plug device.
|
||
|
|
||
|
**/
|
||
|
BOOLEAN
|
||
|
IsHotPlugDevice (
|
||
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
||
|
)
|
||
|
{
|
||
|
EFI_DEVICE_PATH_PROTOCOL *CheckDevicePath;
|
||
|
|
||
|
CheckDevicePath = DevicePath;
|
||
|
while (!IsDevicePathEnd (CheckDevicePath)) {
|
||
|
//
|
||
|
// Check device whether is hot plug device or not throught Device Path
|
||
|
//
|
||
|
if ((DevicePathType (CheckDevicePath) == MESSAGING_DEVICE_PATH) &&
|
||
|
(DevicePathSubType (CheckDevicePath) == MSG_USB_DP ||
|
||
|
DevicePathSubType (CheckDevicePath) == MSG_USB_CLASS_DP ||
|
||
|
DevicePathSubType (CheckDevicePath) == MSG_USB_WWID_DP)) {
|
||
|
//
|
||
|
// If Device is USB device
|
||
|
//
|
||
|
return TRUE;
|
||
|
}
|
||
|
if ((DevicePathType (CheckDevicePath) == HARDWARE_DEVICE_PATH) &&
|
||
|
(DevicePathSubType (CheckDevicePath) == HW_PCCARD_DP)) {
|
||
|
//
|
||
|
// If Device is PCCard
|
||
|
//
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
CheckDevicePath = NextDevicePathNode (CheckDevicePath);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|