Enhanced TerminalDxe module not to install Simple Text(ex) input protocol and Simple Text output protocol, if the device path to the handle is not present in the ConIn and ConOut/ConErr environment variables.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9852 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
vanjeff 2010-01-28 12:29:25 +00:00
parent af176a83f9
commit e3dcffcc48
2 changed files with 707 additions and 480 deletions

View File

@ -218,6 +218,186 @@ TerminalDriverBindingSupported (
return Status; return Status;
} }
/**
Build the terminal device path for the child device according to the
terminal type.
@param ParentDevicePath Parent device path.
@param RemainingDevicePath A specific child device.
@return The child device path built.
**/
EFI_DEVICE_PATH_PROTOCOL*
EFIAPI
BuildTerminalDevpath (
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath;
UINT8 TerminalType;
VENDOR_DEVICE_PATH *Node;
EFI_STATUS Status;
TerminalDevicePath = NULL;
TerminalType = PCANSITYPE;
//
// Use the RemainingDevicePath to determine the terminal type
//
Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;
if (Node == NULL) {
TerminalType = PCANSITYPE;
} else 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 {
return NULL;
}
//
// Build the device path for the child device
//
Status = SetTerminalDevicePath (
TerminalType,
ParentDevicePath,
&TerminalDevicePath
);
if (EFI_ERROR (Status)) {
return NULL;
}
return TerminalDevicePath;
}
/**
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;
}
/**
Check whether the terminal device path is in the global variable.
@param VariableName Pointer to one global variable.
@param TerminalDevicePath Pointer to the terminal device's device path.
@retval TRUE The devcie is in the global variable.
@retval FALSE The devcie is not in the global variable.
**/
BOOLEAN
IsTerminalInConsoleVariable (
IN CHAR16 *VariableName,
IN EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath
)
{
EFI_DEVICE_PATH_PROTOCOL *Variable;
BOOLEAN ReturnFlag;
//
// Get global variable and its size according to the name given.
//
Variable = GetEfiGlobalVariable (VariableName);
if (Variable == NULL) {
return FALSE;
}
//
// Check whether the terminal device path is one of the variable instances.
//
ReturnFlag = MatchDevicePaths (Variable, TerminalDevicePath);
FreePool (Variable);
return ReturnFlag;
}
/**
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;
}
/** /**
Start this driver on Controller by opening a Serial IO protocol, Start this driver on Controller by opening a Serial IO protocol,
reading Device Path, and creating a child handle with a Simple Text In, reading Device Path, and creating a child handle with a Simple Text In,
@ -256,9 +436,22 @@ TerminalDriverBindingStart (
UINTN Index; UINTN Index;
EFI_DEVICE_PATH_PROTOCOL *DevicePath; EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextInput;
BOOLEAN ConInSelected;
BOOLEAN ConOutSelected;
BOOLEAN NullRemaining;
BOOLEAN SimTxtInInstalled;
BOOLEAN SimTxtOutInstalled;
BOOLEAN FirstEnter;
TerminalDevice = NULL; TerminalDevice = NULL;
DefaultNode = NULL; DefaultNode = NULL;
ConInSelected = FALSE;
ConOutSelected = FALSE;
NullRemaining = TRUE;
SimTxtInInstalled = FALSE;
SimTxtOutInstalled = FALSE;
FirstEnter = FALSE;
// //
// Get the Device Path Protocol to build the device path of the child device // Get the Device Path Protocol to build the device path of the child device
// //
@ -291,7 +484,14 @@ TerminalDriverBindingStart (
if (Status != EFI_ALREADY_STARTED) { if (Status != EFI_ALREADY_STARTED) {
// //
// If Serial I/O is not already open by this driver, then tag the handle // the serial I/O protocol never be opened before, it is the first
// time to start the serial Io controller
//
FirstEnter = TRUE;
}
//
// 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 // with the Terminal Driver GUID and update the ConInDev, ConOutDev, and
// StdErrDev variables with the list of possible terminal types on this // StdErrDev variables with the list of possible terminal types on this
// serial port. // serial port.
@ -325,7 +525,45 @@ TerminalDriverBindingStart (
TerminalUpdateConsoleDevVariable (L"ErrOutDev", ParentDevicePath); TerminalUpdateConsoleDevVariable (L"ErrOutDev", ParentDevicePath);
} }
} }
//
// Check the requirement for the SimpleTxtIn and SimpleTxtOut protocols
//
// Simple In/Out Protocol will not be installed onto the handle if the
// device path to the handle is not present in the ConIn/ConOut
// environment variable. But If RemainingDevicePath is NULL, then always
// produce both Simple In and Simple Text Output Protocols. This is required
// for the connect all sequences to make sure all possible consoles are
// produced no matter what the current values of ConIn, ConOut, or StdErr are.
//
if (RemainingDevicePath == NULL) {
NullRemaining = TRUE;
} }
DevicePath = BuildTerminalDevpath (ParentDevicePath, RemainingDevicePath);
if (DevicePath != NULL) {
ConInSelected = IsTerminalInConsoleVariable (L"ConIn", DevicePath);
ConOutSelected = IsTerminalInConsoleVariable (L"ConOut", DevicePath);
FreePool (DevicePath);
} else {
goto Error;
}
//
// Not create the child terminal handle if both Simple In/In Ex and
// Simple text Out protocols are not required to be published
//
if ((!ConInSelected)&&(!ConOutSelected)&&(!NullRemaining)) {
goto Error;
}
//
// create the child terminal handle during first entry
//
if (FirstEnter) {
//
// First enther the start funciton
//
FirstEnter = FALSE;
// //
// Make sure a child handle does not already exist. This driver can only // Make sure a child handle does not already exist. This driver can only
// produce one child per serial port. // produce one child per serial port.
@ -346,9 +584,10 @@ TerminalDriverBindingStart (
FreePool (OpenInfoBuffer); FreePool (OpenInfoBuffer);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
return Status; goto Error;
} }
} }
// //
// If RemainingDevicePath is NULL, then create default device path node // If RemainingDevicePath is NULL, then create default device path node
// //
@ -416,7 +655,6 @@ TerminalDriverBindingStart (
goto Error; goto Error;
} }
Status = gBS->CreateEvent ( Status = gBS->CreateEvent (
EVT_NOTIFY_WAIT, EVT_NOTIFY_WAIT,
TPL_NOTIFY, TPL_NOTIFY,
@ -477,30 +715,6 @@ TerminalDriverBindingStart (
TerminalDevice->SerialInTimeOut = SerialInTimeOut; 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;
}
//
// Set Simple Text Output Protocol from template. // Set Simple Text Output Protocol from template.
// //
SimpleTextOutput = CopyMem ( SimpleTextOutput = CopyMem (
@ -623,20 +837,24 @@ TerminalDriverBindingStart (
break; break;
} }
// //
// Install protocol interfaces for the serial device. // Build the device path for the child device
// //
Status = gBS->InstallMultipleProtocolInterfaces ( Status = SetTerminalDevicePath (
TerminalDevice->TerminalType,
ParentDevicePath,
&TerminalDevice->DevicePath
);
if (EFI_ERROR (Status)) {
goto Error;
}
Status = gBS->InstallProtocolInterface (
&TerminalDevice->Handle, &TerminalDevice->Handle,
&gEfiDevicePathProtocolGuid, &gEfiDevicePathProtocolGuid,
TerminalDevice->DevicePath, EFI_NATIVE_INTERFACE,
&gEfiSimpleTextInProtocolGuid, TerminalDevice->DevicePath
&TerminalDevice->SimpleInput,
&gEfiSimpleTextInputExProtocolGuid,
&TerminalDevice->SimpleInputEx,
&gEfiSimpleTextOutProtocolGuid,
&TerminalDevice->SimpleTextOutput,
NULL
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Error; goto Error;
@ -657,7 +875,152 @@ TerminalDriverBindingStart (
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Error; goto Error;
} }
}
//
// Find the child handle, and get its TerminalDevice private data
//
Status = gBS->OpenProtocolInformation (
Controller,
&gEfiSerialIoProtocolGuid,
&OpenInfoBuffer,
&EntryCount
);
if (!EFI_ERROR (Status)) {
Status = EFI_NOT_FOUND;
ASSERT (OpenInfoBuffer != NULL);
for (Index = 0; Index < EntryCount; Index++) {
if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
//
// Find the child terminal handle.
// Test whether the SimpleTxtIn and SimpleTxtOut have been published
//
Status = gBS->OpenProtocol (
OpenInfoBuffer[Index].ControllerHandle,
&gEfiSimpleTextInProtocolGuid,
(VOID **) &SimpleTextInput,
This->DriverBindingHandle,
OpenInfoBuffer[Index].ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (!EFI_ERROR (Status)) {
SimTxtInInstalled = TRUE;
TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput);
}
Status = gBS->OpenProtocol (
OpenInfoBuffer[Index].ControllerHandle,
&gEfiSimpleTextOutProtocolGuid,
(VOID **) &SimpleTextOutput,
This->DriverBindingHandle,
OpenInfoBuffer[Index].ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (!EFI_ERROR (Status)) {
SimTxtOutInstalled = TRUE;
TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
}
Status = EFI_SUCCESS;
break;
}
}
FreePool (OpenInfoBuffer);
if (EFI_ERROR (Status)) {
goto ReportError;
}
} else {
goto ReportError;
}
ASSERT (TerminalDevice != NULL);
//
// Only do the reset if the device path is in the Conout variable
//
if (ConInSelected && !SimTxtInInstalled) {
Status = TerminalDevice->SimpleInput.Reset (
&TerminalDevice->SimpleInput,
FALSE
);
if (EFI_ERROR (Status)) {
//
// Need to report Error Code first
//
goto ReportError;
}
}
//
// Only output the configure string to remote terminal if the device path
// is in the Conout variable
//
if (ConOutSelected && !SimTxtOutInstalled) {
Status = TerminalDevice->SimpleTextOutput.SetAttribute (
&TerminalDevice->SimpleTextOutput,
EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
);
if (EFI_ERROR (Status)) {
goto ReportError;
}
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;
}
}
//
// Simple In/Out Protocol will not be installed onto the handle if the
// device path to the handle is not present in the ConIn/ConOut
// environment variable. But If RemainingDevicePath is NULL, then always
// produce both Simple In and Simple Text Output Protocols. This is required
// for the connect all sequences to make sure all possible consoles are
// produced no matter what the current values of ConIn, ConOut, or StdErr are.
//
if (!SimTxtInInstalled && (ConInSelected || NullRemaining)) {
Status = gBS->InstallMultipleProtocolInterfaces (
&TerminalDevice->Handle,
&gEfiSimpleTextInProtocolGuid,
&TerminalDevice->SimpleInput,
&gEfiSimpleTextInputExProtocolGuid,
&TerminalDevice->SimpleInputEx,
NULL
);
if (EFI_ERROR (Status)) {
goto Error;
}
}
if (!SimTxtOutInstalled && (ConOutSelected || NullRemaining)) {
Status = gBS->InstallProtocolInterface (
&TerminalDevice->Handle,
&gEfiSimpleTextOutProtocolGuid,
EFI_NATIVE_INTERFACE,
&TerminalDevice->SimpleTextOutput
);
if (EFI_ERROR (Status)) {
goto Error;
}
}
if (DefaultNode != NULL) { if (DefaultNode != NULL) {
FreePool (DefaultNode); FreePool (DefaultNode);
} }
@ -668,6 +1031,7 @@ ReportError:
// //
// Report error code before exiting // Report error code before exiting
// //
DevicePath = ParentDevicePath;
REPORT_STATUS_CODE_WITH_DEVICE_PATH ( REPORT_STATUS_CODE_WITH_DEVICE_PATH (
EFI_ERROR_CODE | EFI_ERROR_MINOR, EFI_ERROR_CODE | EFI_ERROR_MINOR,
(EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR), (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
@ -902,41 +1266,6 @@ TerminalDriverBindingStop (
return EFI_SUCCESS; return EFI_SUCCESS;
} }
/**
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;
}
/** /**
Update terminal device path in Console Device Environment Variables. Update terminal device path in Console Device Environment Variables.
@ -957,16 +1286,14 @@ TerminalUpdateConsoleDevVariable (
EFI_DEVICE_PATH_PROTOCOL *NewVariable; EFI_DEVICE_PATH_PROTOCOL *NewVariable;
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
Variable = NULL;
// //
// Get global variable and its size according to the name given. // Get global variable and its size according to the name given.
// //
Variable = TerminalGetVariableAndSize ( Variable = GetEfiGlobalVariable (VariableName);
VariableName, if (Variable == NULL) {
&gEfiGlobalVariableGuid, return;
&VariableSize }
);
// //
// Append terminal device path onto the variable. // Append terminal device path onto the variable.
// //
@ -1026,17 +1353,12 @@ TerminalRemoveConsoleDevVariable (
EFI_DEVICE_PATH_PROTOCOL *SavedNewVariable; EFI_DEVICE_PATH_PROTOCOL *SavedNewVariable;
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
Variable = NULL;
Instance = NULL; Instance = NULL;
// //
// Get global variable and its size according to the name given. // Get global variable and its size according to the name given.
// //
Variable = TerminalGetVariableAndSize ( Variable = GetEfiGlobalVariable (VariableName);
VariableName,
&gEfiGlobalVariableGuid,
&VariableSize
);
if (Variable == NULL) { if (Variable == NULL) {
return ; return ;
} }
@ -1116,81 +1438,6 @@ TerminalRemoveConsoleDevVariable (
return ; return ;
} }
/**
Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
buffer, and the size of the buffer. On failure return NULL.
@param Name String part of EFI variable name
@param VendorGuid GUID part of EFI variable name
@param VariableSize Returns the size of the EFI variable that was read
@return Dynamically allocated memory that contains a copy of the EFI variable.
Caller is responsible freeing the buffer. If variable was not read,
NULL returned.
**/
VOID *
TerminalGetVariableAndSize (
IN CHAR16 *Name,
IN EFI_GUID *VendorGuid,
OUT UINTN *VariableSize
)
{
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
//
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;
FreePool (Buffer);
Buffer = NULL;
}
} else {
//
// Variable not found or other errors met.
//
BufferSize = 0;
FreePool (Buffer);
Buffer = NULL;
}
*VariableSize = BufferSize;
return Buffer;
}
/** /**
Build terminal device path according to terminal type. Build terminal device path according to terminal type.

View File

@ -1,7 +1,7 @@
/** @file /** @file
Header file for Terminal driver. Header file for Terminal driver.
Copyright (c) 2006 - 2008, Intel Corporation. <BR> Copyright (c) 2006 - 2010, Intel Corporation. <BR>
All rights reserved. This program and the accompanying materials All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 which accompanies this distribution. The full text of the license may be found at
@ -836,26 +836,6 @@ TerminalRemoveConsoleDevVariable (
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
); );
/**
Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
buffer, and the size of the buffer. On failure return NULL.
@param Name String part of EFI variable name
@param VendorGuid GUID part of EFI variable name
@param VariableSize Returns the size of the EFI variable that was read
@return Dynamically allocated memory that contains a copy of the EFI variable.
Caller is repsoncible freeing the buffer. If variable was not read,
NULL regturned.
**/
VOID *
TerminalGetVariableAndSize (
IN CHAR16 *Name,
IN EFI_GUID *VendorGuid,
OUT UINTN *VariableSize
);
/** /**
Build termial device path according to terminal type. Build termial device path according to terminal type.