578 lines
15 KiB
C
578 lines
15 KiB
C
/** @file
|
|
CrServiceDxe driver
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2012 - 2013, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
#include "CrServiceDxe.h"
|
|
#include "CrVariableUpdate.h"
|
|
#include "CrLegacySupport.h"
|
|
|
|
BOOLEAN mCrEnable;
|
|
BOOLEAN mHeadless;
|
|
EFI_HANDLE mCrServiceImageHandle;
|
|
H2O_BDS_CP_HANDLE mCpConOutHandle;
|
|
CR_POLICY_VARIABLE mCrPolicy;
|
|
|
|
extern CR_DEVICES_SETTING_HEAD_NODE mCrVarDeviceHead;
|
|
extern UINT32 mCrBaudRateTable[];
|
|
|
|
|
|
EFI_STATUS
|
|
DummyQueryVgaScreenBuffer (
|
|
IN EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL *This,
|
|
IN OUT UINTN *ScreenBuffer,
|
|
IN OUT UINTN *ScreenAttributes
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
EFI_STATUS
|
|
DummyDisconnectCrsTerminal (
|
|
EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL *This,
|
|
UINTN TerminalNumber
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
EFI_STATUS
|
|
DummyconnectCrsTerminal (
|
|
EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL *This,
|
|
UINTN TerminalNumber
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
Query Consplitter screen buffer and attribute buffer
|
|
|
|
@param This A pointer to the EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL instance.
|
|
@param ScreenBuffer A pointer to current screen buffer.
|
|
@param ScreenAttributes A pointer to current attribute buffer.
|
|
|
|
@retval EFI_SUCCESS Get Screen Buffer Success
|
|
@retval EFI_UNSUPPORTED Get Screen Buffer fail
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
QueryVgaScreenBuffer (
|
|
IN EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL *This,
|
|
IN OUT UINTN *ScreenBuffer,
|
|
IN OUT UINTN *ScreenAttributes
|
|
)
|
|
{
|
|
UINTN ConsplitterScreenBuf;
|
|
UINTN ConsplitterAttrBuf;
|
|
|
|
ConsplitterScreenBuf = 0;
|
|
ConsplitterAttrBuf = 0;
|
|
|
|
ConsplitterScreenBuf = (UINTN)PcdGet64 (PcdDevNullScreenPtr);
|
|
ConsplitterAttrBuf = (UINTN)PcdGet64 (PcdDevNullAttributes);
|
|
if (ConsplitterScreenBuf == 0 || ConsplitterAttrBuf == 0) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
*ScreenBuffer = ConsplitterScreenBuf;
|
|
*ScreenAttributes = ConsplitterAttrBuf;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
Disconnect Console Redirection Terminal controller.
|
|
|
|
@param This A pointer to the EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL instance.
|
|
@param TerminalNumber Specify the terminal index that will be disconnect. The first index number is 0.
|
|
|
|
@retval EFI_SUCCESS Disconnect success
|
|
@retval EFI_INVALID_PARAMETER The Terminal number is invalid
|
|
@retval others Disconnect fail
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DisconnectCrTerminal (
|
|
IN EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL *This,
|
|
IN UINTN TerminalNumber
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_CONSOLE_REDIRECTION_INFO *CrInfo;
|
|
EFI_DEVICE_PATH_PROTOCOL *ChildDevicePath;
|
|
EFI_HANDLE ChildHandle;
|
|
EFI_HANDLE ParentHandle;
|
|
|
|
CrInfo = This->CRInfo;
|
|
|
|
if (TerminalNumber >= CrInfo->DeviceCount) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ChildDevicePath = CrInfo->CRDevice[TerminalNumber].DevicePath;
|
|
Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid , &ChildDevicePath, &ChildHandle);
|
|
|
|
if (!EFI_ERROR (Status) && IsDevicePathEnd (ChildDevicePath)) {
|
|
Status = GetParentHandle (ChildHandle, &ParentHandle);
|
|
if (!EFI_ERROR(Status)) {
|
|
Status = gBS->DisconnectController (ParentHandle, NULL, NULL);
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
Connect Console Redirection Terminal controller.
|
|
|
|
@param This A pointer to the EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL instance.
|
|
@param TerminalNumber Specify the terminal index that will be Connect. The first index number is 0.
|
|
|
|
@retval EFI_SUCCESS Connect success
|
|
@retval EFI_INVALID_PARAMETER The Terminal number is invalid
|
|
@retval EFI_ABORTED Can't duplicate device path.
|
|
@retval others Connect fail
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ConnectCrTerminal (
|
|
IN EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL *This,
|
|
IN UINTN TerminalNumber
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_CONSOLE_REDIRECTION_INFO *CrInfo;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *OriginalDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
|
|
EFI_HANDLE ParentHandle;
|
|
|
|
CrInfo = This->CRInfo;
|
|
|
|
if (TerminalNumber >= CrInfo->DeviceCount) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
OriginalDevicePath = DuplicateDevicePath (CrInfo->CRDevice[TerminalNumber].DevicePath);
|
|
if (OriginalDevicePath == NULL) {
|
|
return EFI_ABORTED;
|
|
}
|
|
RemainingDevicePath = CrInfo->CRDevice[TerminalNumber].DevicePath;
|
|
DevicePath = OriginalDevicePath;
|
|
TruncateLastNode (DevicePath);
|
|
PointToLastNode (&RemainingDevicePath);
|
|
|
|
Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid , &DevicePath, &ParentHandle);
|
|
|
|
if (!EFI_ERROR (Status) && IsDevicePathEnd (DevicePath)) {
|
|
Status = gBS->ConnectController (ParentHandle, NULL, RemainingDevicePath, TRUE);
|
|
}
|
|
gBS->FreePool (OriginalDevicePath);
|
|
return Status;
|
|
}
|
|
|
|
|
|
EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL mDummyCRService = {
|
|
NULL,
|
|
DummyQueryVgaScreenBuffer,
|
|
DummyDisconnectCrsTerminal,
|
|
DummyconnectCrsTerminal
|
|
};
|
|
|
|
EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL mCrService = {
|
|
NULL,
|
|
QueryVgaScreenBuffer,
|
|
DisconnectCrTerminal,
|
|
ConnectCrTerminal
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
@param
|
|
|
|
@retval
|
|
|
|
**/
|
|
BOOLEAN
|
|
IsHeadlessPlatform (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN NumHandles;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN Index;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
PCI_TYPE00 PciConfig;
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiPciIoProtocolGuid,
|
|
NULL,
|
|
&NumHandles,
|
|
&HandleBuffer
|
|
);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
return TRUE;
|
|
}
|
|
|
|
for (Index = 0; Index < NumHandles; Index++) {
|
|
Status = gBS->HandleProtocol (
|
|
HandleBuffer[Index],
|
|
&gEfiPciIoProtocolGuid,
|
|
(VOID **) &PciIo
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
continue;
|
|
}
|
|
|
|
Status = PciIo->Pci.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
0,
|
|
sizeof(PCI_TYPE00),
|
|
&PciConfig
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
continue;
|
|
}
|
|
|
|
if (PciConfig.Hdr.ClassCode[2] == PCI_CLASS_DISPLAY) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
CrSafeFreePool (HandleBuffer);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
|
|
|
|
@param
|
|
|
|
@retval
|
|
|
|
**/
|
|
VOID
|
|
UpdateCrStatus (
|
|
VOID
|
|
)
|
|
{
|
|
CR_POLICY_VARIABLE *Tmp;
|
|
|
|
Tmp = NULL;
|
|
Tmp = (CR_POLICY_VARIABLE*) CommonGetVariableData (CR_POLICY_NAME, &gH2OCrConfigurationGuid);
|
|
if (Tmp == NULL) {
|
|
mCrEnable = FALSE;
|
|
DEBUG ((EFI_D_INFO, "\nCr << %a >> C.R. Disable\n", __FUNCTION__));
|
|
return;
|
|
}
|
|
|
|
CopyMem (&mCrPolicy, Tmp, sizeof(CR_POLICY_VARIABLE));
|
|
mCrEnable = TRUE;
|
|
|
|
if (IsHeadlessPlatform()) {
|
|
mHeadless = TRUE;
|
|
mCrEnable = TRUE;
|
|
} else {
|
|
mHeadless = FALSE;
|
|
}
|
|
DEBUG ((EFI_D_INFO, "\nCr << %a >> C.R. Enable, Headless:%d\n", __FUNCTION__, mHeadless));
|
|
FreePool (Tmp);
|
|
}
|
|
|
|
UINTN
|
|
GetNumberOfActiveCrDevice (
|
|
VOID
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
CR_DEVICES_SETTING_NODE *CrDevNode;
|
|
UINTN Count;
|
|
|
|
Count = 0;
|
|
Link = GetFirstNode (&mCrVarDeviceHead.Link);
|
|
while (!IsNull (&mCrVarDeviceHead.Link, Link)) {
|
|
CrDevNode = CR_DEVICE_SETTING_FROM_THIS (Link);
|
|
if (CrDevNode->AddIntoConVar == FALSE) {
|
|
Link = GetNextNode (&mCrVarDeviceHead.Link, Link);
|
|
continue;
|
|
}
|
|
Count++;
|
|
Link = GetNextNode (&mCrVarDeviceHead.Link, Link);
|
|
}
|
|
return Count;
|
|
}
|
|
|
|
EFI_CONSOLE_REDIRECTION_INFO *
|
|
BuildCrInfo (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN DeviceCount;
|
|
UINTN DeviceIndex;
|
|
UINTN BufferSize;
|
|
EFI_CONSOLE_REDIRECTION_INFO *CRInfo;
|
|
LIST_ENTRY *Link;
|
|
CR_DEVICES_SETTING_NODE *CrDevNode;
|
|
EFI_DEVICE_PATH *RemainDevPath;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevPathProtocol;
|
|
EFI_STATUS Status;
|
|
H2O_UART_16550_ACCESS_PROTOCOL *Uart16550Protocol;
|
|
UART_16550_DEVICE_INFO *DeviceInfo;
|
|
|
|
CRInfo = NULL;
|
|
DeviceIndex = 0;
|
|
DeviceCount = GetNumberOfActiveCrDevice ();
|
|
if (DeviceCount == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
BufferSize = sizeof(EFI_CONSOLE_REDIRECTION_INFO) + (DeviceCount * sizeof (EFI_CONSOLE_REDIRECTION_DEVICE));
|
|
|
|
CRInfo = AllocateZeroPool (BufferSize);
|
|
if (CRInfo == NULL) {
|
|
return CRInfo;
|
|
}
|
|
|
|
CRInfo->Headless = mHeadless;
|
|
|
|
Link = GetFirstNode (&mCrVarDeviceHead.Link);
|
|
while (!IsNull (&mCrVarDeviceHead.Link, Link)) {
|
|
CrDevNode = CR_DEVICE_SETTING_FROM_THIS (Link);
|
|
if (CrDevNode->AddIntoConVar == FALSE) {
|
|
Link = GetNextNode (&mCrVarDeviceHead.Link, Link);
|
|
continue;
|
|
}
|
|
|
|
RemainDevPath = GetDevicePathFromCrDevSetting(CrDevNode->CrSetting);
|
|
Status = GetProtocolWithLocateDevicePath (&gH2OCrUart16550AccessProtocolGuid, &RemainDevPath, &Uart16550Protocol);
|
|
if (EFI_ERROR (Status)) {
|
|
Link = GetNextNode (&mCrVarDeviceHead.Link, Link);
|
|
continue;
|
|
}
|
|
DeviceInfo = Uart16550Protocol->DeviceInfo;
|
|
|
|
CRInfo->CRDevice[DeviceIndex].Uart16550protocol = Uart16550Protocol;
|
|
CRInfo->CRDevice[DeviceIndex].Type = DeviceInfo->DeviceType;
|
|
CRInfo->CRDevice[DeviceIndex].BaudRateDivisor = (UINT8)(DeviceInfo->SerialClockFreq / DeviceInfo->SampleRate / mCrBaudRateTable[CrDevNode->CrSetting->Attribute.BaudRate]);
|
|
|
|
RemainDevPath = GetDevicePathFromCrDevSetting(CrDevNode->CrSetting);
|
|
Status = GetProtocolWithLocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainDevPath, &DevPathProtocol);
|
|
if (!EFI_ERROR (Status)) {
|
|
CRInfo->CRDevice[DeviceIndex].DevicePath = DevPathProtocol;
|
|
}
|
|
|
|
Link = GetNextNode (&mCrVarDeviceHead.Link, Link);
|
|
DeviceIndex ++;
|
|
}
|
|
|
|
CRInfo->DeviceCount = (UINT8)DeviceIndex;
|
|
return CRInfo;
|
|
}
|
|
|
|
/**
|
|
Before connect console device, CRservice need to add CR devices path into ConIn/ConOut variable.
|
|
|
|
@param
|
|
|
|
@retval
|
|
|
|
**/
|
|
VOID
|
|
BeforeConnectConsoleCallback (
|
|
IN EFI_EVENT Event,
|
|
IN H2O_BDS_CP_HANDLE Handle
|
|
)
|
|
{
|
|
static BOOLEAN IsDone = FALSE;
|
|
|
|
if (IsDone == TRUE) {
|
|
return;
|
|
}
|
|
IsDone = TRUE;
|
|
|
|
//
|
|
// If SCU set CrEnable or headless then set CrEnable.
|
|
//
|
|
UpdateCrStatus ();
|
|
|
|
//
|
|
// Create a temp device list for access current Cr Device Variable.
|
|
//
|
|
CreateCrDeviceVarList ();
|
|
|
|
//
|
|
// Update CR device setting value from H2OSerialConfigLib
|
|
//
|
|
UpdateCrDeviceSetting ();
|
|
|
|
//
|
|
// Add Enable CR devices to ConIn/ConOut Variable
|
|
//
|
|
UpdateConInConOutVarFromActiveDevicePath ();
|
|
|
|
}
|
|
|
|
VOID
|
|
AfterConnectConOutCallBack (
|
|
IN EFI_EVENT Event,
|
|
IN H2O_BDS_CP_HANDLE Handle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
if (mCrEnable) {
|
|
//
|
|
// Check the select Cr devices still in Con Variable?
|
|
// If CR device connect fail then set exist = false.
|
|
//
|
|
CheckAndSaveConnectResult (mConOutVarName, mConVarGuid);
|
|
CreateNewActiveCrDevice ();
|
|
|
|
//
|
|
// Prepare CrInfo and reinstall protocol
|
|
//
|
|
mCrService.CRInfo = BuildCrInfo ();
|
|
gBS->ReinstallProtocolInterface (
|
|
mCrServiceImageHandle,
|
|
&gH2OConsoleRedirectionServiceProtocolGuid,
|
|
&mDummyCRService,
|
|
&mCrService
|
|
);
|
|
|
|
//
|
|
// If there have Cr device, prepare option rom
|
|
//
|
|
if (mCrService.CRInfo != NULL) {
|
|
Status = CrOpRomSupport ( mCrService.CRInfo);
|
|
DEBUG ((DEBUG_INFO, "\nCr << CrOpRomSupport >> %r\n", Status));
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// CrHookDxe driver entry always install CRService protocol for avoid headless platform
|
|
// no CouOut device. please reference ForceActiveVga function.
|
|
//
|
|
gBS->UninstallProtocolInterface (
|
|
mCrServiceImageHandle,
|
|
&gH2OConsoleRedirectionServiceProtocolGuid,
|
|
&mDummyCRService
|
|
);
|
|
}
|
|
|
|
BdsCpUnregisterHandler (mCpConOutHandle);
|
|
}
|
|
|
|
VOID
|
|
AfterConnectAllCallBack (
|
|
IN EFI_EVENT Event,
|
|
IN H2O_BDS_CP_HANDLE Handle
|
|
)
|
|
{
|
|
if (mCrEnable) {
|
|
//
|
|
// Update device's exist-status that are non-exist before,
|
|
// or now disappear device.
|
|
//
|
|
UpdateDevicesExistStatus ();
|
|
|
|
//
|
|
// Check * device exist? if true create new variable
|
|
//
|
|
FindAsteriskDevicePath ();
|
|
|
|
//
|
|
// Free Temp Cr device variable list
|
|
//
|
|
FreeCrDevicesVarList ();
|
|
}
|
|
}
|
|
|
|
/**
|
|
The driver entry point.
|
|
|
|
@param ImageHandle A handle for the image that is initializing this driver
|
|
@param SystemTable A pointer to the EFI system table
|
|
|
|
@retval EFI_SUCCESS: Driver initialized successfully
|
|
@retval others Driver initialized unsuccessfully
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CrServiceEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
H2O_BDS_CP_HANDLE CpHandle;
|
|
|
|
mCrServiceImageHandle = ImageHandle;
|
|
InitializeCrDeviceList ();
|
|
|
|
Status = gBS->InstallProtocolInterface (
|
|
&ImageHandle,
|
|
&gH2OConsoleRedirectionServiceProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&mDummyCRService
|
|
);
|
|
|
|
//
|
|
// Register Callback function
|
|
//
|
|
Status = BdsCpRegisterHandler (
|
|
&gH2OBdsCpConInConnectBeforeProtocolGuid,
|
|
BeforeConnectConsoleCallback,
|
|
H2O_BDS_CP_HIGH,
|
|
&CpHandle
|
|
);
|
|
|
|
Status = BdsCpRegisterHandler (
|
|
&gH2OBdsCpConOutConnectBeforeProtocolGuid,
|
|
BeforeConnectConsoleCallback,
|
|
H2O_BDS_CP_HIGH,
|
|
&CpHandle
|
|
);
|
|
|
|
Status = BdsCpRegisterHandler (
|
|
&gH2OBdsCpConOutConnectAfterProtocolGuid,
|
|
AfterConnectConOutCallBack,
|
|
H2O_BDS_CP_MEDIUM,
|
|
&mCpConOutHandle
|
|
);
|
|
|
|
Status = BdsCpRegisterHandler (
|
|
&gH2OBdsCpConnectAllAfterProtocolGuid,
|
|
AfterConnectAllCallBack,
|
|
H2O_BDS_CP_MEDIUM,
|
|
&CpHandle
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|