865 lines
27 KiB
C
865 lines
27 KiB
C
/** @file
|
|
Hot plug support for H2O form browser
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2013 - 2021, 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 "FBHotPlug.h"
|
|
#include <Guid/ReturnFromImage.h>
|
|
|
|
EFI_EVENT mReadyToBootEvent = NULL;
|
|
BOOLEAN mTriggerByFB = FALSE;
|
|
EFI_HANDLE *mFBHotPlugAddConsoleDevList = NULL;
|
|
UINT32 mFBHotPlugAddConsoleDevCount = 0;
|
|
EFI_HANDLE *mFBHotPlugRemoveConsoleDevList = NULL;
|
|
UINT32 mFBHotPlugRemoveConsoleDevCount = 0;
|
|
|
|
EFI_GUID *mFBHotPlugGuidList[] = {
|
|
&gEfiConsoleInDeviceGuid,
|
|
&gEfiConsoleOutDeviceGuid,
|
|
//
|
|
// SetupMouse will produce AbsolutePointer and SimplePointer
|
|
//
|
|
//&gEfiAbsolutePointerProtocolGuid,
|
|
//&gEfiSimplePointerProtocolGuid
|
|
};
|
|
|
|
EFI_DRIVER_BINDING_PROTOCOL mFBHotPlugDriverBinding = {
|
|
FBHotPlugDriverBindingSupported,
|
|
FBHotPlugDriverBindingStart,
|
|
FBHotPlugDriverBindingStop,
|
|
0x9,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL mFBHotPlugComponentName = {
|
|
FBHotPlugComponentNameGetDriverName,
|
|
FBHotPlugComponentNameGetControllerName,
|
|
"eng"
|
|
};
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL mFBHotPlugComponentName2 = {
|
|
(EFI_COMPONENT_NAME2_GET_DRIVER_NAME) FBHotPlugComponentNameGetDriverName,
|
|
(EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) FBHotPlugComponentNameGetControllerName,
|
|
"en"
|
|
};
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mFBHotPlugDriverNameTable[] = {
|
|
{
|
|
"eng;en",
|
|
L"H2O Form Browser Driver"
|
|
},
|
|
{
|
|
NULL,
|
|
NULL
|
|
}
|
|
};
|
|
|
|
EFI_SIMPLE_TEXT_INPUT_PROTOCOL mFakeSimpleInput = {
|
|
FakeSimpleTextInReset,
|
|
FakeSimpleTextInReadKeyStroke,
|
|
NULL
|
|
};
|
|
|
|
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL mFakeSimpleInputEx = {
|
|
FakeSimpleTextInExReset,
|
|
FakeSimpleTextInExReadKeyStrokeEx,
|
|
NULL,
|
|
FakeSimpleTextInExSetState,
|
|
FakeSimpleTextInExRegisterKeyNotify,
|
|
FakeSimpleTextInExUnregisterKeyNotify
|
|
};
|
|
|
|
EFI_SIMPLE_POINTER_MODE mFakeSimplePointerMode;
|
|
EFI_SIMPLE_POINTER_PROTOCOL mFakeSimplePointer = {
|
|
FakeSimplePointerReset,
|
|
FakeSimplePointerGetState,
|
|
NULL,
|
|
&mFakeSimplePointerMode
|
|
};
|
|
|
|
EFI_ABSOLUTE_POINTER_MODE mAbsolutePointerMode;
|
|
EFI_ABSOLUTE_POINTER_PROTOCOL mAbsolutePointer = {
|
|
FakeAbsolutePointerReset,
|
|
FakeAbsolutePointerGetState,
|
|
NULL,
|
|
&mAbsolutePointerMode
|
|
};
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FakeSimpleTextInReset (
|
|
IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
|
|
IN BOOLEAN ExtendedVerification
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FakeSimpleTextInReadKeyStroke (
|
|
IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
|
|
OUT EFI_INPUT_KEY *Key
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FakeSimpleTextInExReset (
|
|
IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
|
|
IN BOOLEAN ExtendedVerification
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FakeSimpleTextInExReadKeyStrokeEx (
|
|
IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
|
|
OUT EFI_KEY_DATA *KeyData
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FakeSimpleTextInExSetState (
|
|
IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
|
|
IN EFI_KEY_TOGGLE_STATE *KeyToggleState
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FakeSimpleTextInExRegisterKeyNotify (
|
|
IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
|
|
IN EFI_KEY_DATA *KeyData,
|
|
IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
|
|
OUT EFI_HANDLE *NotifyHandle
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FakeSimpleTextInExUnregisterKeyNotify (
|
|
IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
|
|
IN EFI_HANDLE NotificationHandle
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FakeSimplePointerReset (
|
|
IN EFI_SIMPLE_POINTER_PROTOCOL *This,
|
|
IN BOOLEAN ExtendedVerification
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FakeSimplePointerGetState (
|
|
IN EFI_SIMPLE_POINTER_PROTOCOL *This,
|
|
IN OUT EFI_SIMPLE_POINTER_STATE *State
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FakeAbsolutePointerReset (
|
|
IN EFI_ABSOLUTE_POINTER_PROTOCOL *This,
|
|
IN BOOLEAN ExtendedVerification
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FakeAbsolutePointerGetState (
|
|
IN EFI_ABSOLUTE_POINTER_PROTOCOL *This,
|
|
IN OUT EFI_ABSOLUTE_POINTER_STATE *State
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
Retrieves a Unicode string that is the user readable name of the driver.
|
|
|
|
This function retrieves the user readable name of a driver in the form of a Unicode string.
|
|
If the driver specified by This has a user readable name in the language specified by Language,
|
|
then a pointer to the driver name is returned in DriverName, and EFI_SUCCESS is returned.
|
|
If the driver specified by This does not support the language specified by Language, then EFI_UNSUPPORTED is returned.
|
|
|
|
@param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or EFI_COMPONENT_NAME_PROTOCOL instance.
|
|
@param[in] Language A pointer to a Null-terminated ASCII string array indicating the language.
|
|
This is the language of the driver name that the caller is requesting,
|
|
and it must match one of the languages specified in SupportedLanguages.
|
|
The number of languages supported by a driver is up to the driver writer.
|
|
Language is specified in RFC 4646 or ISO 639-2 language code format.
|
|
@param[out] DriverName A pointer to the Unicode string to return. This Unicode string is the name of the
|
|
driver specified by This in the language specified by Language.
|
|
|
|
@retval EFI_SUCCESS The Unicode string for the Driver specified by
|
|
This and the language specified by Language was returned in DriverName.
|
|
@retval EFI_INVALID_PARAMETER Language is NULL.
|
|
@retval EFI_INVALID_PARAMETER DriverName is NULL.
|
|
@retval EFI_UNSUPPORTED The driver specified by This does not support the language specified by Language.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FBHotPlugComponentNameGetDriverName (
|
|
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
|
IN CHAR8 *Language,
|
|
OUT CHAR16 **DriverName
|
|
)
|
|
{
|
|
return LookupUnicodeString2 (
|
|
Language,
|
|
This->SupportedLanguages,
|
|
mFBHotPlugDriverNameTable,
|
|
DriverName,
|
|
(BOOLEAN)(This == &mFBHotPlugComponentName)
|
|
);
|
|
}
|
|
|
|
/**
|
|
Retrieves a Unicode string that is the user readable name of the controller that is being managed by a driver.
|
|
|
|
This function retrieves the user readable name of the controller specified by ControllerHandle and
|
|
ChildHandle in the form of a Unicode string. If the driver specified by This has a user readable name in the
|
|
language specified by Language, then a pointer to the controller name is returned in ControllerName,
|
|
and EFI_SUCCESS is returned. If the driver specified by This is not currently managing the controller specified
|
|
by ControllerHandle and ChildHandle, then EFI_UNSUPPORTED is returned. If the driver specified by This does not
|
|
support the language specified by Language, then EFI_UNSUPPORTED is returned.
|
|
|
|
@param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or EFI_COMPONENT_NAME_PROTOCOL instance.
|
|
@param[in] ControllerHandle The handle of a controller that the driver specified by This is managing.
|
|
This handle specifies the controller whose name is to be returned.
|
|
@param[in] ChildHandle The handle of the child controller to retrieve the name of.This is an optional
|
|
parameter that may be NULL. It will be NULL for device drivers. It will also be NULL
|
|
for a bus drivers that wish to retrieve the name of the bus controller.
|
|
It will not be NULL for a bus driver that wishes to retrieve the name of a child controller.
|
|
@param[in] Language A pointer to a Null-terminated ASCII string array indicating the language.
|
|
This is the language of the driver name that the caller is requesting, and it must
|
|
match one of the languages specified in SupportedLanguages. The number of languages
|
|
supported by a driver is up to the driver writer. Language is specified in
|
|
RFC 4646 or ISO 639-2 language code format.
|
|
@param[out] ControllerName A pointer to the Unicode string to return. This Unicode string is the name of the
|
|
controller specified by ControllerHandle and ChildHandle in the language specified by
|
|
Language from the point of view of the driver specified by This.
|
|
|
|
@retval EFI_SUCCESS The Unicode string for the user readable name in the language specified by Language for
|
|
the driver specified by This was returned in DriverName.
|
|
@retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
|
|
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
|
|
@retval EFI_INVALID_PARAMETER Language is NULL.
|
|
@retval EFI_INVALID_PARAMETER ControllerName is NULL.
|
|
@retval EFI_UNSUPPORTED The driver specified by This is not currently managing the controller specified by
|
|
ControllerHandle and ChildHandle.
|
|
@retval EFI_UNSUPPORTED The driver specified by This does not support the language specified by Language.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FBHotPlugComponentNameGetControllerName (
|
|
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_HANDLE ChildHandle OPTIONAL,
|
|
IN CHAR8 *Language,
|
|
OUT CHAR16 **ControllerName
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
BOOLEAN
|
|
IsConsoleDevPresent (
|
|
IN EFI_HANDLE Handle
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
|
|
for (Index = 0; Index < mConsoleDevListCount; Index++) {
|
|
if (mConsoleDevList[Index]->Handle == Handle) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Add console device into target console device list
|
|
|
|
@param[in] ConsoleHandle Console device handle
|
|
@param[in, out] ConsoleDevList Pointer to output console device list
|
|
@param[in, out] ConsoleDevCount Pointer to the number of output console device list
|
|
|
|
@retval EFI_SUCCESS Add console device successfully
|
|
@retval EFI_INVALID_PARAMETER ConsoleDevList or ConsoleDevCount is NULL
|
|
@retval EFI_OUT_OF_RESOURCES Allocate pool fail
|
|
|
|
**/
|
|
EFI_STATUS
|
|
AddConsoleIntoList (
|
|
IN EFI_HANDLE ConsoleHandle,
|
|
IN OUT EFI_HANDLE **ConsoleDevList,
|
|
IN OUT UINT32 *ConsoleDevCount
|
|
)
|
|
{
|
|
EFI_HANDLE *NewList;
|
|
|
|
if (ConsoleDevList == NULL || ConsoleDevCount == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
NewList = AllocatePool ((*ConsoleDevCount + 1) * sizeof (EFI_HANDLE));
|
|
if (NewList == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
if (*ConsoleDevList != NULL) {
|
|
CopyMem (NewList, *ConsoleDevList, *ConsoleDevCount * sizeof (EFI_HANDLE));
|
|
FreePool (*ConsoleDevList);
|
|
}
|
|
NewList[*ConsoleDevCount] = ConsoleHandle;
|
|
|
|
*ConsoleDevList = NewList;
|
|
*ConsoleDevCount += 1;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Remove console device in form browser.
|
|
For console output device, it will be detach from display engine.
|
|
For non console input device, console device data will be deleted form browser private data
|
|
For console input device, input protocol pointer will be pointed to fake protocol instance.
|
|
It can make sure that inturrupted process can still go until the process is finished.
|
|
|
|
@retval EFI_SUCCESS Stop console device successfully
|
|
@retval EFI_NOT_FOUND Can not find the console device data by ControllerHandle
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
RemoveConsoleDev (
|
|
IN EFI_HANDLE ControllerHandle
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
H2O_FORM_BROWSER_CONSOLE_DEV *ConsoleDev;
|
|
H2O_DISPLAY_ENGINE_PROTOCOL *H2ODisplayEngine;
|
|
|
|
for (Index = 0; Index < mConsoleDevListCount; Index++) {
|
|
if (mConsoleDevList[Index]->Handle == ControllerHandle) {
|
|
break;
|
|
}
|
|
}
|
|
if (Index == mConsoleDevListCount) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
ConsoleDev = mConsoleDevList[Index];
|
|
|
|
if (IsConOutDeviceType (ConsoleDev->DeviceType)) {
|
|
for (Index = 0; Index < mFBPrivate.EngineListCount; Index++) {
|
|
H2ODisplayEngine = mFBPrivate.EngineList[Index].DisplayEngine;
|
|
|
|
if (CompareGuid (&H2ODisplayEngine->Id, &ConsoleDev->DisplayEngine)) {
|
|
H2ODisplayEngine->DetachConsole (H2ODisplayEngine, ConsoleDev);
|
|
mFBPrivate.EngineList[Index].AttachedConsoleCount--;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!IsConInDeviceType (ConsoleDev->DeviceType)) {
|
|
return FBRemoveConsoleDevice (&mFBPrivate, ControllerHandle);
|
|
}
|
|
|
|
AddConsoleIntoList (ControllerHandle, &mFBHotPlugRemoveConsoleDevList, &mFBHotPlugRemoveConsoleDevCount);
|
|
|
|
//
|
|
// Replace the protocol pointer to fake protocol instance. Form browser will remove device from private data
|
|
// after the interrupted process is finished.
|
|
//
|
|
for (Index = 0; Index < mInputEventListCount; Index++) {
|
|
if (mInputEventDescList[Index].Handle == ControllerHandle) {
|
|
switch (mInputEventDescList[Index].DeviceType) {
|
|
|
|
case H2O_FORM_BROWSER_CONSOLE_STI:
|
|
mInputEventDescList[Index].Protocol = &mFakeSimpleInput;
|
|
break;
|
|
|
|
case H2O_FORM_BROWSER_CONSOLE_STI2:
|
|
mInputEventDescList[Index].Protocol = &mFakeSimpleInputEx;
|
|
break;
|
|
|
|
case H2O_FORM_BROWSER_CONSOLE_SP:
|
|
mInputEventDescList[Index].Protocol = &mFakeSimplePointer;
|
|
break;
|
|
|
|
case H2O_FORM_BROWSER_CONSOLE_AP:
|
|
mInputEventDescList[Index].Protocol = &mAbsolutePointer;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Test to see if console device could be supported on the Controller.
|
|
|
|
@param[in] This Driver Binding protocol instance pointer.
|
|
@param[in] ControllerHandle Handle of device to test.
|
|
@param[in] RemainingDevicePath Optional parameter use to pick a specific child device to start.
|
|
|
|
@retval EFI_SUCCESS This driver supports this device.
|
|
@retval EFI_UNSUPPORTED This driver does not support this device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FBHotPlugDriverBindingSupported (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VOID *Instance;
|
|
UINT32 Index;
|
|
UINT32 Count;
|
|
|
|
Status = gBS->OpenProtocol (
|
|
ControllerHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
NULL,
|
|
This->DriverBindingHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (!mTriggerByFB && IsConsoleDeviceType (ControllerHandle)) {
|
|
//
|
|
// Add device handle in list. Form browser will start to install device into private data
|
|
// after current interrupted event is finished.
|
|
//
|
|
AddConsoleIntoList (ControllerHandle, &mFBHotPlugAddConsoleDevList, &mFBHotPlugAddConsoleDevCount);
|
|
}
|
|
|
|
Count = sizeof (mFBHotPlugGuidList) / sizeof (EFI_GUID *);
|
|
for (Index = 0; Index < Count; Index++) {
|
|
Status = gBS->OpenProtocol (
|
|
ControllerHandle,
|
|
mFBHotPlugGuidList[Index],
|
|
&Instance,
|
|
This->DriverBindingHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
gBS->CloseProtocol (
|
|
ControllerHandle,
|
|
mFBHotPlugGuidList[Index],
|
|
This->DriverBindingHandle,
|
|
ControllerHandle
|
|
);
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
Start hot plug functinoality on device handle.
|
|
|
|
@param[in] This Driver Binding protocol instance pointer.
|
|
@param[in] ControllerHandle Handle of device to bind driver to.
|
|
@param[in] RemainingDevicePath Optional parameter use to pick a specific child device to start.
|
|
|
|
@retval EFI_SUCCESS Hot plug functinoality is added to ControllerHandle.
|
|
@retval EFI_UNSUPPORTED Hot plug functinoality does not support this device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FBHotPlugDriverBindingStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOLEAN OpenSuccess;
|
|
VOID *Instance;
|
|
UINT32 Index;
|
|
UINT32 Count;
|
|
|
|
OpenSuccess = FALSE;
|
|
Count = sizeof (mFBHotPlugGuidList) / sizeof (EFI_GUID *);
|
|
for (Index = 0; Index < Count; Index++) {
|
|
Status = gBS->OpenProtocol (
|
|
ControllerHandle,
|
|
mFBHotPlugGuidList[Index],
|
|
&Instance,
|
|
This->DriverBindingHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
OpenSuccess = TRUE;
|
|
}
|
|
}
|
|
if (!OpenSuccess) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
FBConsplitterAddDevice (ControllerHandle);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Stop hot plug functionality on ControllerHandle by closing console devcice GUID.
|
|
|
|
@param[in] This Driver Binding protocol instance pointer.
|
|
@param[in] ControllerHandle Handle of device to stop driver on
|
|
@param[in] NumberOfChildren Number of Handles in ChildHandleBuffer.
|
|
If number of children is zero stop the entire bus driver.
|
|
@param[in] ChildHandleBuffer List of Child Handles to Stop.
|
|
|
|
@retval EFI_SUCCESS This driver is removed ControllerHandle
|
|
@retval other This driver was not removed from this device
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FBHotPlugDriverBindingStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOLEAN CloseSuccess;
|
|
UINT32 Index;
|
|
UINT32 Count;
|
|
|
|
FBConsplitterDeleteDevice (ControllerHandle);
|
|
|
|
if (!mTriggerByFB) {
|
|
RemoveConsoleDev (ControllerHandle);
|
|
}
|
|
|
|
CloseSuccess = FALSE;
|
|
Count = sizeof (mFBHotPlugGuidList) / sizeof (EFI_GUID *);
|
|
for (Index = 0; Index < Count; Index++) {
|
|
Status = gBS->CloseProtocol (
|
|
ControllerHandle,
|
|
mFBHotPlugGuidList[Index],
|
|
This->DriverBindingHandle,
|
|
ControllerHandle
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
CloseSuccess = TRUE;
|
|
}
|
|
}
|
|
if (!CloseSuccess) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
EFIAPI
|
|
FBBootFromImageReturnNotifyFun (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
gBS->CloseEvent (Event);
|
|
|
|
FBInitConsoles (&mFBPrivate);
|
|
mFBPrivate.Repaint = TRUE;
|
|
}
|
|
|
|
VOID
|
|
FBHotPlugEvtFunc (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_EVENT ImageReturnEvent;
|
|
VOID *Registration;
|
|
|
|
if (mReadyToBootEvent != NULL) {
|
|
gBS->CloseEvent (mReadyToBootEvent);
|
|
mReadyToBootEvent = NULL;
|
|
}
|
|
|
|
FBDetachConsoles (&mFBPrivate);
|
|
|
|
Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, FBBootFromImageReturnNotifyFun, NULL, &ImageReturnEvent);
|
|
if (!EFI_ERROR (Status)) {
|
|
gBS->RegisterProtocolNotify (&gReturnFromImageGuid, ImageReturnEvent, &Registration);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Initialize hot plug functionality
|
|
|
|
@retval EFI_SUCCESS Initialize hot plug functionality successfully
|
|
@retval other Install driver binding protocol fail
|
|
|
|
**/
|
|
EFI_STATUS
|
|
FBHotPlugInit (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 Index;
|
|
UINTN NumberOfHandle;
|
|
EFI_HANDLE *HandleBuffer;
|
|
|
|
FBConsplitterInit ();
|
|
|
|
Status = EfiLibInstallDriverBindingComponentName2 (
|
|
gImageHandle,
|
|
gST,
|
|
&mFBHotPlugDriverBinding,
|
|
gImageHandle,
|
|
&mFBHotPlugComponentName,
|
|
&mFBHotPlugComponentName2
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
mTriggerByFB = TRUE;
|
|
HandleBuffer = NULL;
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiDevicePathProtocolGuid,
|
|
NULL,
|
|
&NumberOfHandle,
|
|
&HandleBuffer
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
for (Index = 0; Index < NumberOfHandle; Index++) {
|
|
if (IsConsoleDeviceType (HandleBuffer[Index])) {
|
|
gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);
|
|
}
|
|
}
|
|
}
|
|
FBFreePool ((VOID **) &HandleBuffer);
|
|
mTriggerByFB = FALSE;
|
|
|
|
FBConsplitterStart ();
|
|
|
|
mReadyToBootEvent = NULL;
|
|
EfiCreateEventReadyToBootEx (TPL_CALLBACK, FBHotPlugEvtFunc, NULL, &mReadyToBootEvent);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Close hot plug functionality
|
|
|
|
@retval EFI_SUCCESS Close hot plug functionality successfully
|
|
@retval EFI_UNSUPPORTED No need to shutdown hot plug functionality
|
|
**/
|
|
EFI_STATUS
|
|
FBHotPlugShutdown (
|
|
VOID
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
|
|
if (mFBHotPlugDriverBinding.DriverBindingHandle == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (mReadyToBootEvent != NULL) {
|
|
gBS->CloseEvent (mReadyToBootEvent);
|
|
mReadyToBootEvent = NULL;
|
|
}
|
|
|
|
//
|
|
// Undo console devices from mFBHotPlugDriverBinding protocol
|
|
//
|
|
mTriggerByFB = TRUE;
|
|
for (Index = 0; Index < mConsoleDevListCount; Index++) {
|
|
gBS->DisconnectController (mConsoleDevList[Index]->Handle, mFBHotPlugDriverBinding.DriverBindingHandle, NULL);
|
|
}
|
|
mTriggerByFB = FALSE;
|
|
|
|
gBS->UninstallMultipleProtocolInterfaces (
|
|
gImageHandle,
|
|
&gEfiDriverBindingProtocolGuid,
|
|
&mFBHotPlugDriverBinding,
|
|
&gEfiComponentNameProtocolGuid,
|
|
&mFBHotPlugComponentName,
|
|
&gEfiComponentName2ProtocolGuid,
|
|
&mFBHotPlugComponentName2,
|
|
NULL
|
|
);
|
|
mFBHotPlugDriverBinding.DriverBindingHandle = NULL;
|
|
mFBHotPlugDriverBinding.ImageHandle = NULL;
|
|
|
|
FBConsplitterShutdown ();
|
|
//
|
|
// Bind console devices on original driver binding protocol (ConSplitter), because
|
|
// mFBHotPlugDriverBinding protocol use EFI_OPEN_PROTOCOL_EXCLUSIVE open mode which
|
|
// make original driver binding protocol is disconnected
|
|
//
|
|
//
|
|
// Because ConSplitter will restore DevNullScreen to physical console device, perform clean screen avoid screen flash.
|
|
//
|
|
gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
|
|
gST->ConOut->ClearScreen (gST->ConOut);
|
|
for (Index = 0; Index < mConsoleDevListCount; Index++) {
|
|
gBS->ConnectController (mConsoleDevList[Index]->Handle, NULL, NULL, FALSE);
|
|
}
|
|
gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
|
|
gST->ConOut->ClearScreen (gST->ConOut);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Process hot plug functionality for new console devices.
|
|
It will add devices in private data and attach on display engine for console output device
|
|
|
|
@retval EFI_SUCCESS Process hot plug functionality successfully
|
|
|
|
**/
|
|
EFI_STATUS
|
|
FBHotPlugEventFunc (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 Index;
|
|
H2O_FORM_BROWSER_CONSOLE_DEV *ConsoleDev;
|
|
EFI_TPL OriginalTpl;
|
|
BOOLEAN NeedToRefresh;
|
|
|
|
if ((mFBHotPlugAddConsoleDevCount == 0 || mFBHotPlugAddConsoleDevList == NULL) &&
|
|
(mFBHotPlugRemoveConsoleDevCount == 0 || mFBHotPlugRemoveConsoleDevList == NULL)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
OriginalTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
|
|
|
//
|
|
// Process plug-in device
|
|
//
|
|
NeedToRefresh = FALSE;
|
|
|
|
|
|
//
|
|
// Process removed device
|
|
//
|
|
if (mFBHotPlugRemoveConsoleDevList != NULL) {
|
|
for (Index = 0; Index < mFBHotPlugRemoveConsoleDevCount; Index++) {
|
|
FBRemoveConsoleDevice (&mFBPrivate, mFBHotPlugRemoveConsoleDevList[Index]);
|
|
}
|
|
}
|
|
mFBHotPlugRemoveConsoleDevCount = 0;
|
|
FBFreePool ((VOID **) &mFBHotPlugRemoveConsoleDevList);
|
|
|
|
if (mFBHotPlugAddConsoleDevList != NULL) {
|
|
for (Index = 0; Index < mFBHotPlugAddConsoleDevCount; Index++) {
|
|
if (IsConsoleDevPresent (mFBHotPlugAddConsoleDevList[Index])) {
|
|
continue;
|
|
}
|
|
|
|
ConsoleDev = FBAddConsoleDevice (&mFBPrivate, mFBHotPlugAddConsoleDevList[Index]);
|
|
if (ConsoleDev == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if (IsConOutDeviceType (ConsoleDev->DeviceType)) {
|
|
RemoveConsoleDev (gST->ConsoleOutHandle);
|
|
|
|
Status = AttachToDE (ConsoleDev);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
FBConsplitterUpdateModeData ();
|
|
|
|
NeedToRefresh = TRUE;
|
|
}
|
|
|
|
if (IsConInDeviceType (ConsoleDev->DeviceType)) {
|
|
FBAddConInDev (&mFBPrivate, ConsoleDev);
|
|
}
|
|
}
|
|
}
|
|
mFBHotPlugAddConsoleDevCount = 0;
|
|
FBFreePool ((VOID **) &mFBHotPlugAddConsoleDevList);
|
|
|
|
//
|
|
// If no physical console output device, attach ConSplitter's console device.
|
|
//
|
|
if (!HasConOutDevice ()) {
|
|
if (IsConsoleDeviceType (gST->ConsoleOutHandle)) {
|
|
ConsoleDev = FBAddConsoleDevice (&mFBPrivate, gST->ConsoleOutHandle);
|
|
if (ConsoleDev != NULL) {
|
|
AttachToDE (ConsoleDev);
|
|
NeedToRefresh = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NeedToRefresh) {
|
|
FBRepaint (&mFBPrivate);
|
|
NeedToRefresh = FALSE;
|
|
}
|
|
gBS->RestoreTPL (OriginalTpl);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|