alder_lake_bios/Insyde/InsydeSetupPkg/Drivers/H2OFormBrowserDxe/FBEvent.c

2922 lines
92 KiB
C

/** @file
Event for formbrowser
;******************************************************************************
;* 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 "InternalH2OFormBrowser.h"
#include <Protocol/SetupMouse.h>
#include <Protocol/Cpu.h>
#include <Protocol/H2OSubmitSvc.h>
BOOLEAN mRefreshFormSet = FALSE;
BOOLEAN mRefreshForm = FALSE;
EFI_EVENT *mInputEventList = NULL;
H2O_INPUT_EVENT_DESCRIPTION *mInputEventDescList = NULL;
UINT32 mInputEventListCount = 0;
LIST_ENTRY mEventQueue = INITIALIZE_LIST_HEAD_VARIABLE (mEventQueue);
EFI_LOCK mEventQueueLock = {TPL_CALLBACK, 4, 1};
EFI_GUID mScuFormSetGuid = {0x9f85453e, 0x2f03, 0x4989, 0xad, 0x3b, 0x4a, 0x84, 0x07, 0x91, 0xaf, 0x3a};
EFI_GUID mSecureBootMgrFormSetGuid = {0xaa1305b9, 0x1f3, 0x4afb, 0x92, 0xe, 0xc9, 0xb9, 0x79, 0xa8, 0x52, 0xfd};
extern EFI_HII_HANDLE mCurrentHiiHandle;
extern EFI_GUID mCurrentFormSetGuid;
extern UINT16 mCurrentFormId;
extern BOOLEAN mHiiPackageListUpdated;
extern UINT16 mCurFakeQestId;
extern BOOLEAN mFinishRetrieveCall;
STATIC FORM_DISPLAY_ENGINE_STATEMENT mDisplayStatement;
USER_INPUT *gUserInput;
FORM_DISPLAY_ENGINE_FORM *gFormData = NULL;
#define TICKS_PER_MS 10000U
/**
Trigger form browser idle before checkpoint.
*/
STATIC
VOID
TriggerCpFormBrowserIdleBefore (
VOID
)
{
H2O_BDS_CP_FORM_BROWSER_IDLE_BEFORE_DATA BdsFormBrowserIdleBeforeData;
BdsFormBrowserIdleBeforeData.Size = sizeof (H2O_BDS_CP_FORM_BROWSER_IDLE_BEFORE_DATA);
BdsFormBrowserIdleBeforeData.Status = H2O_BDS_TASK_NORMAL;
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpFormBrowserIdleBeforeGuid));
H2OCpTrigger (&gH2OBdsCpFormBrowserIdleBeforeGuid, &BdsFormBrowserIdleBeforeData);
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsFormBrowserIdleBeforeData.Status));
}
/**
Trigger form browser idle after checkpoint.
*/
STATIC
VOID
TriggerCpFormBrowserIdleAfter (
VOID
)
{
H2O_BDS_CP_FORM_BROWSER_IDLE_AFTER_DATA BdsFormBrowserIdleAfterData;
BdsFormBrowserIdleAfterData.Size = sizeof (H2O_BDS_CP_FORM_BROWSER_IDLE_AFTER_DATA);
BdsFormBrowserIdleAfterData.Status = H2O_BDS_TASK_NORMAL;
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpFormBrowserIdleAfterGuid));
H2OCpTrigger (&gH2OBdsCpFormBrowserIdleAfterGuid, &BdsFormBrowserIdleAfterData);
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsFormBrowserIdleAfterData.Status));
}
/**
Trigger form browser user input checkpoint.
@param[in, out] Event A double pointer to the user input event.
@retval EFI_SUCCESS Trigger form browser user input checkpoint successfully.
@retval EFI_INVALID_PARAMETER Input parameter is NULL or invalid.
*/
STATIC
EFI_STATUS
TriggerCpFormBrowserUserInput (
IN OUT H2O_DISPLAY_ENGINE_EVT **Event
)
{
H2O_DISPLAY_ENGINE_EVT *InputEvent;
H2O_BDS_CP_FORM_BROWSER_USER_INPUT_DATA BdsCpUserInput;
if (Event == NULL || *Event == NULL) {
return EFI_INVALID_PARAMETER;
}
InputEvent = *Event;
ZeroMem (&BdsCpUserInput, sizeof (BdsCpUserInput));
BdsCpUserInput.Size = sizeof (H2O_BDS_CP_FORM_BROWSER_USER_INPUT_DATA);
BdsCpUserInput.Status = H2O_BDS_TASK_NORMAL;
if (InputEvent->Type == H2O_DISPLAY_ENGINE_EVT_TYPE_KEYPRESS) {
BdsCpUserInput.UserInputType = H2O_BDS_CP_FORM_BROWSER_USER_INPUT_KEYPRESS;
CopyMem (&BdsCpUserInput.KeyData , &(((H2O_DISPLAY_ENGINE_EVT_KEYPRESS *) InputEvent)->KeyData) , sizeof (EFI_KEY_DATA));
} else if (InputEvent->Type == H2O_DISPLAY_ENGINE_EVT_TYPE_REL_PTR_MOVE) {
BdsCpUserInput.UserInputType = H2O_BDS_CP_FORM_BROWSER_USER_INPUT_SIMPLE_POINTER;
CopyMem (&BdsCpUserInput.SimplePtrState, &(((H2O_DISPLAY_ENGINE_EVT_REL_PTR_MOVE *) InputEvent)->State) , sizeof (EFI_SIMPLE_POINTER_STATE));
} else if (InputEvent->Type == H2O_DISPLAY_ENGINE_EVT_TYPE_ABS_PTR_MOVE) {
BdsCpUserInput.UserInputType = H2O_BDS_CP_FORM_BROWSER_USER_INPUT_ABSOLUTE_POINTER;
CopyMem (&BdsCpUserInput.AbsPtrState , &(((H2O_DISPLAY_ENGINE_EVT_ABS_PTR_MOVE *) InputEvent)->AbsPtrState), sizeof (EFI_ABSOLUTE_POINTER_STATE));
}
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpFormBrowserUserInputGuid));
H2OCpTrigger (&gH2OBdsCpFormBrowserUserInputGuid, &BdsCpUserInput);
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsCpUserInput.Status));
if (BdsCpUserInput.Status == H2O_CP_TASK_SKIP) {
FreePool (*Event);
*Event = NULL;
goto Skip;
} else if (BdsCpUserInput.Status == H2O_CP_TASK_UPDATE) {
if (InputEvent->Type == H2O_DISPLAY_ENGINE_EVT_TYPE_KEYPRESS) {
CopyMem (&(((H2O_DISPLAY_ENGINE_EVT_KEYPRESS *) InputEvent)->KeyData) , &BdsCpUserInput.KeyData , sizeof (EFI_KEY_DATA));
} else if (InputEvent->Type == H2O_DISPLAY_ENGINE_EVT_TYPE_REL_PTR_MOVE) {
CopyMem (&(((H2O_DISPLAY_ENGINE_EVT_REL_PTR_MOVE *) InputEvent)->State) , &BdsCpUserInput.SimplePtrState, sizeof (EFI_SIMPLE_POINTER_STATE));
} else if (InputEvent->Type == H2O_DISPLAY_ENGINE_EVT_TYPE_ABS_PTR_MOVE) {
CopyMem (&(((H2O_DISPLAY_ENGINE_EVT_ABS_PTR_MOVE *) InputEvent)->AbsPtrState), &BdsCpUserInput.AbsPtrState , sizeof (EFI_ABSOLUTE_POINTER_STATE));
}
}
Skip:
return EFI_SUCCESS;
}
/**
Call EFI_HII_CONFIG_ACCESS_PROTOCOL.Callback function.
@param[in] ConfigAccess Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
@param[in] Action Specifies the type of action taken by the browser.
@param[in] QuestionId A unique value which is sent to the original
exporting driver so that it can identify the type
of data to expect. The format of the data tends to
vary based on the opcode that generated the callback.
@param[in] Type The type of value for the question.
@param[in] ValueSize Value size.
@param[in, out] Value A pointer to the data being sent to the original
exporting driver.
@param[out] ActionRequest On return, points to the action requested by the
callback function.
@param[in] FormsetGuid Pointer to formset GUID.
@param[in] FormId Form ID.
@retval EFI_SUCCESS The callback successfully handled the action.
@retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
@retval Other Error status returned from Callback function.
**/
EFI_STATUS
FBCallCallbackFn (
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess,
IN EFI_BROWSER_ACTION Action,
IN EFI_QUESTION_ID QuestionId,
IN UINT8 Type,
IN UINTN ValueSize,
IN OUT EFI_IFR_TYPE_VALUE *Value,
OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest,
IN EFI_GUID *FormsetGuid,
IN UINT16 FormId
)
{
EFI_STATUS Status;
if (FeaturePcdGet (PcdH2OBdsCpFormBrowserCallbackBeforeSupported)) {
H2O_BDS_CP_FORM_BROWSER_CALLBACK_BEFORE_DATA CallbackBeforeData;
EFI_IFR_TYPE_VALUE TempValue;
EFI_IFR_TYPE_VALUE *TempValuePtr;
if (Type == EFI_IFR_TYPE_BUFFER) {
TempValuePtr = AllocateCopyPool (ValueSize, Value);
if (TempValuePtr == NULL) {
return EFI_OUT_OF_RESOURCES;
}
} else {
CopyMem (&TempValue, Value, sizeof (EFI_IFR_TYPE_VALUE));
TempValuePtr = &TempValue;
}
Status = EFI_UNSUPPORTED;
CallbackBeforeData.Size = sizeof (H2O_BDS_CP_FORM_BROWSER_CALLBACK_BEFORE_DATA);
CallbackBeforeData.Status = H2O_BDS_TASK_NORMAL;
CallbackBeforeData.Action = Action;
CallbackBeforeData.QuestionId = QuestionId;
CallbackBeforeData.Type = Type;
CallbackBeforeData.Value = TempValuePtr;
CallbackBeforeData.ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
CallbackBeforeData.CallbackStatus = Status;
CallbackBeforeData.FormId = FormId;
CopyGuid (&CallbackBeforeData.FormsetGuid, FormsetGuid);
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpFormBrowserCallbackBeforeGuid));
H2OCpTrigger (&gH2OBdsCpFormBrowserCallbackBeforeGuid, &CallbackBeforeData);
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", CallbackBeforeData.Status));
if (CallbackBeforeData.Status == H2O_CP_TASK_SKIP_UPDATE) {
Status = CallbackBeforeData.CallbackStatus;
}
if (CallbackBeforeData.Status == H2O_CP_TASK_UPDATE ||
CallbackBeforeData.Status == H2O_CP_TASK_SKIP_UPDATE) {
*ActionRequest = CallbackBeforeData.ActionRequest;
CopyMem (Value, CallbackBeforeData.Value, ValueSize);
}
if (Type == EFI_IFR_TYPE_BUFFER) {
FreePool (CallbackBeforeData.Value);
}
if (CallbackBeforeData.Status == H2O_CP_TASK_SKIP ||
CallbackBeforeData.Status == H2O_CP_TASK_SKIP_UPDATE) {
goto Skip;
}
}
Status = ConfigAccess->Callback (
ConfigAccess,
Action,
QuestionId,
Type,
Value,
ActionRequest
);
Skip:
if (FeaturePcdGet (PcdH2OBdsCpFormBrowserCallbackAfterSupported)) {
H2O_BDS_CP_FORM_BROWSER_CALLBACK_AFTER_DATA CallbackAfterData;
EFI_IFR_TYPE_VALUE TempValue;
EFI_IFR_TYPE_VALUE *TempValuePtr;
if (Type == EFI_IFR_TYPE_BUFFER) {
TempValuePtr = AllocateCopyPool (ValueSize, Value);
if (TempValuePtr == NULL) {
return EFI_OUT_OF_RESOURCES;
}
} else {
CopyMem (&TempValue, Value, sizeof (EFI_IFR_TYPE_VALUE));
TempValuePtr = &TempValue;
}
CallbackAfterData.Size = sizeof (H2O_BDS_CP_FORM_BROWSER_CALLBACK_AFTER_DATA);
CallbackAfterData.Status = H2O_BDS_TASK_NORMAL;
CallbackAfterData.Action = Action;
CallbackAfterData.QuestionId = QuestionId;
CallbackAfterData.Type = Type;
CallbackAfterData.Value = TempValuePtr;
CallbackAfterData.ActionRequest = (EFI_ERROR (Status)) ? EFI_BROWSER_ACTION_REQUEST_NONE : *ActionRequest;
CallbackAfterData.CallbackStatus = Status;
CallbackAfterData.FormId = FormId;
CopyGuid (&CallbackAfterData.FormsetGuid, FormsetGuid);
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpFormBrowserCallbackAfterGuid));
H2OCpTrigger (&gH2OBdsCpFormBrowserCallbackAfterGuid, &CallbackAfterData);
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", CallbackAfterData.Status));
if (CallbackAfterData.Status == H2O_CP_TASK_UPDATE) {
Status = CallbackAfterData.CallbackStatus;
*ActionRequest = CallbackAfterData.ActionRequest;
CopyMem (Value, CallbackAfterData.Value, ValueSize);
}
if (Type == EFI_IFR_TYPE_BUFFER) {
FreePool (CallbackAfterData.Value);
}
}
return Status;
}
/**
Call EFI_HII_CONFIG_ROUTING_PROTOCOL.ExtractConfig function.
@param[in] Request A null-terminated string in <MultiConfigRequest> format.
@param[out] Progress On return, points to a character in the
Request string. Points to the string's null
terminator if the request was successful. Points
to the most recent '&' before the first
failing name / value pair (or the beginning
of the string if the failure is in the first
name / value pair) if the request was not
successful
@param[out] Results A null-terminated string in <MultiConfigAltResp> format
which has all values filled in for the names in the
Request string.
@retval EFI_SUCCESS The Results string is filled with the values corresponding to all requested names.
@retval Other Error status returned from ExtractConfig function.
**/
EFI_STATUS
FBCallExtractConfigFn (
IN CONST EFI_STRING Request,
OUT EFI_STRING *Progress,
OUT EFI_STRING *Results
)
{
EFI_STATUS Status;
if (FeaturePcdGet (PcdH2OBdsCpFormBrowserExtractConfigBeforeSupported)) {
H2O_BDS_CP_FORM_BROWSER_EXTRACT_CONFIG_BEFORE_DATA ExtractConfigBeforeData;
Status = EFI_UNSUPPORTED;
ExtractConfigBeforeData.Size = sizeof (H2O_BDS_CP_FORM_BROWSER_EXTRACT_CONFIG_BEFORE_DATA);
ExtractConfigBeforeData.Status = H2O_BDS_TASK_NORMAL;
ExtractConfigBeforeData.Request = Request;
ExtractConfigBeforeData.Progress = NULL;
ExtractConfigBeforeData.Results = NULL;
ExtractConfigBeforeData.CallbackStatus = Status;
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpFormBrowserExtractConfigBeforeGuid));
H2OCpTrigger (&gH2OBdsCpFormBrowserExtractConfigBeforeGuid, &ExtractConfigBeforeData);
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", ExtractConfigBeforeData.Status));
if (ExtractConfigBeforeData.Status == H2O_CP_TASK_SKIP_UPDATE) {
Status = ExtractConfigBeforeData.CallbackStatus;
}
if (ExtractConfigBeforeData.Status == H2O_CP_TASK_UPDATE ||
ExtractConfigBeforeData.Status == H2O_CP_TASK_SKIP_UPDATE) {
*Progress = ExtractConfigBeforeData.Progress;
*Results = ExtractConfigBeforeData.Results;
}
if (ExtractConfigBeforeData.Status == H2O_CP_TASK_SKIP ||
ExtractConfigBeforeData.Status == H2O_CP_TASK_SKIP_UPDATE) {
goto Skip;
}
}
Status = gHiiConfigRouting->ExtractConfig (
gHiiConfigRouting,
Request,
Progress,
Results
);
Skip:
if (FeaturePcdGet (PcdH2OBdsCpFormBrowserExtractConfigAfterSupported)) {
H2O_BDS_CP_FORM_BROWSER_EXTRACT_CONFIG_AFTER_DATA ExtractConfigAfterData;
ExtractConfigAfterData.Size = sizeof (H2O_BDS_CP_FORM_BROWSER_EXTRACT_CONFIG_AFTER_DATA);
ExtractConfigAfterData.Status = H2O_BDS_TASK_NORMAL;
ExtractConfigAfterData.Request = Request;
ExtractConfigAfterData.Progress = (EFI_ERROR (Status)) ? NULL : *Progress;
ExtractConfigAfterData.Results = (EFI_ERROR (Status)) ? NULL : *Results;
ExtractConfigAfterData.CallbackStatus = Status;
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpFormBrowserExtractConfigAfterGuid));
H2OCpTrigger (&gH2OBdsCpFormBrowserExtractConfigAfterGuid, &ExtractConfigAfterData);
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", ExtractConfigAfterData.Status));
if (ExtractConfigAfterData.Status == H2O_CP_TASK_UPDATE) {
Status = ExtractConfigAfterData.CallbackStatus;
*Progress = ExtractConfigAfterData.Progress;
*Results = ExtractConfigAfterData.Results;
}
}
return Status;
}
/**
Call EFI_HII_CONFIG_ROUTING_PROTOCOL.RouteConfig function.
@param[in] Configuration A null-terminated string in <MulltiConfigResp> format.
@param[out] Progress A pointer to a string filled in with the
offset of the most recent '&' before the
first failing name / value pair (or the
beginning of the string if the failure is in
the first name / value pair), or the
terminating NULL if all was successful.
@retval EFI_SUCCESS The results have been distributed or are awaiting distribution.
@retval Other Error status returned from RouteConfig function.
**/
EFI_STATUS
FBCallRouteConfigFn (
IN CONST EFI_STRING Configuration,
OUT EFI_STRING *Progress
)
{
EFI_STATUS Status;
if (FeaturePcdGet (PcdH2OBdsCpFormBrowserRouteConfigBeforeSupported)) {
H2O_BDS_CP_FORM_BROWSER_ROUTE_CONFIG_BEFORE_DATA RouteConfigBeforeData;
Status = EFI_UNSUPPORTED;
RouteConfigBeforeData.Size = sizeof (H2O_BDS_CP_FORM_BROWSER_ROUTE_CONFIG_BEFORE_DATA);
RouteConfigBeforeData.Status = H2O_BDS_TASK_NORMAL;
RouteConfigBeforeData.Configuration = Configuration;
RouteConfigBeforeData.Progress = NULL;
RouteConfigBeforeData.CallbackStatus = Status;
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpFormBrowserRouteConfigBeforeGuid));
H2OCpTrigger (&gH2OBdsCpFormBrowserRouteConfigBeforeGuid, &RouteConfigBeforeData);
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", RouteConfigBeforeData.Status));
if (RouteConfigBeforeData.Status == H2O_CP_TASK_SKIP_UPDATE) {
Status = RouteConfigBeforeData.CallbackStatus;
}
if (RouteConfigBeforeData.Status == H2O_CP_TASK_UPDATE ||
RouteConfigBeforeData.Status == H2O_CP_TASK_SKIP_UPDATE) {
*Progress = RouteConfigBeforeData.Progress;
}
if (RouteConfigBeforeData.Status == H2O_CP_TASK_SKIP ||
RouteConfigBeforeData.Status == H2O_CP_TASK_SKIP_UPDATE) {
goto Skip;
}
}
Status = gHiiConfigRouting->RouteConfig (
gHiiConfigRouting,
Configuration,
Progress
);
Skip:
if (FeaturePcdGet (PcdH2OBdsCpFormBrowserRouteConfigAfterSupported)) {
H2O_BDS_CP_FORM_BROWSER_ROUTE_CONFIG_AFTER_DATA RouteConfigAfterData;
RouteConfigAfterData.Size = sizeof (H2O_BDS_CP_FORM_BROWSER_ROUTE_CONFIG_AFTER_DATA);
RouteConfigAfterData.Status = H2O_BDS_TASK_NORMAL;
RouteConfigAfterData.Configuration = Configuration;
RouteConfigAfterData.Progress = (EFI_ERROR (Status)) ? NULL : *Progress;
RouteConfigAfterData.CallbackStatus = Status;
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpFormBrowserRouteConfigAfterGuid));
H2OCpTrigger (&gH2OBdsCpFormBrowserRouteConfigAfterGuid, &RouteConfigAfterData);
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", RouteConfigAfterData.Status));
if (RouteConfigAfterData.Status == H2O_CP_TASK_UPDATE) {
Status = RouteConfigAfterData.CallbackStatus;
*Progress = RouteConfigAfterData.Progress;
}
}
return Status;
}
/**
Execute all of the Submit service functions.
@param[out] Request A pointer to the request from the Submit service functions.
Related definition can refer to "Browser actions" of FormBrowserEx.h.
@param[out] ShowSubmitDialog A pointer to the value if needing to show the original submit dialog.
@retval EFI_SUCCESS Execute the Submit service functions successfully.
@retval EFI_Status Otherwise.
*/
EFI_STATUS
EFIAPI
H2OSubmitSvcManager (
OUT UINT32 *Request,
OUT BOOLEAN *ShowSubmitDialog
)
{
EFI_STATUS Status;
UINTN HandleNum;
EFI_HANDLE *HandleBuf;
UINTN Index;
H2O_SUBMIT_SVC_PROTOCOL *SubmitSvc;
UINT32 ChildRequest;
BOOLEAN ChildShowSubmitDialog;
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gH2OSubmitSvcProtocolGuid,
NULL,
&HandleNum,
&HandleBuf
);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
DEBUG ((EFI_D_INFO, "HandleNum: %d \n", HandleNum));
for (Index = 0; Index < HandleNum; Index++) {
ChildRequest = 0;
ChildShowSubmitDialog = TRUE;
Status = gBS->HandleProtocol (
HandleBuf[Index],
&gH2OSubmitSvcProtocolGuid,
(VOID **)&SubmitSvc
);
if (EFI_ERROR (Status)) {
continue;
}
Status = SubmitSvc->ExecuteSvc (SubmitSvc, &ChildRequest, &ChildShowSubmitDialog);
if (!EFI_ERROR (Status)) {
*Request |= ChildRequest;
if (*ShowSubmitDialog != FALSE) {
// Ask FormBrowser not to show the dialog for submit.
*ShowSubmitDialog = ChildShowSubmitDialog;
}
}
}
FreePool (HandleBuf);
return EFI_SUCCESS;
}
FORM_BROWSER_FORM *
GetScuLoadDefaultForm (
IN FORM_BROWSER_FORMSET *FormSet
)
{
LIST_ENTRY *FormLink;
FORM_BROWSER_FORM *Form;
FormLink = GetFirstNode (&FormSet->FormListHead);
Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
while (!IsNull (&FormSet->FormListHead, FormLink)) {
Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
if (Form->FormId == 0xFFFF) {
break;
}
FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
}
return Form;
}
EFI_STATUS
FBNotifyEventToTarget (
IN H2O_FORM_BROWSER_PRIVATE_DATA *Private,
IN CONST H2O_DISPLAY_ENGINE_EVT *Event
)
{
UINT32 Index;
H2O_DISPLAY_ENGINE_PROTOCOL *TargetDE;
if (Event->Target == H2O_FORM_BROWSER_CONSOLE_SYSTEM) {
for (Index = 0; Index < Private->EngineListCount; Index++) {
if (Private->EngineList[Index].AttachedConsoleCount != 0) {
TargetDE = Private->EngineList[Index].DisplayEngine;
TargetDE->Notify (TargetDE, Event);
}
}
} else if (Event->Target != H2O_FORM_BROWSER_CONSOLE_NOT_ASSIGNED) {
if (Private->EngineList[Event->Target - 1].AttachedConsoleCount != 0) {
TargetDE = Private->EngineList[Event->Target - 1].DisplayEngine;
TargetDE->Notify (TargetDE, Event);
}
}
return EFI_SUCCESS;
}
/**
Detect key press.
@param [in] Private Formbrowser private data
@param [in] Event Display engine event type
@retval EFI_SUCCESS Detect key press success.
**/
EFI_STATUS
FBKeyPress (
IN H2O_FORM_BROWSER_PRIVATE_DATA *Private,
IN CONST H2O_DISPLAY_ENGINE_EVT *Event
)
{
H2O_DISPLAY_ENGINE_EVT_KEYPRESS *KeyPress;
UINT32 Index;
INT32 NewActivatedEngine;
H2O_FORM_BROWSER_CONSOLE_DEV *ConsoleDev;
KeyPress = (H2O_DISPLAY_ENGINE_EVT_KEYPRESS *)Event;
//
// change engine by ` key
//
if (KeyPress->KeyData.Key.UnicodeChar == CHAR_TAB &&
(KeyPress->KeyData.KeyState.KeyShiftState & (EFI_RIGHT_ALT_PRESSED | EFI_LEFT_ALT_PRESSED)) != 0) {
//
// Get new NewActivatedEngine
//
NewActivatedEngine = (Private->ActivatedEngine + 1) % Private->EngineListCount;
if (NewActivatedEngine == Private->ActivatedEngine) {
return EFI_SUCCESS;
}
//
// Check has one or more DE is new actived DE and not SerialDevPath
//
for (Index = 0; Index < mConsoleDevListCount; Index++) {
ConsoleDev = mConsoleDevList[Index];
if (IsConInDeviceType (ConsoleDev->DeviceType) || !IsConOutDeviceType (ConsoleDev->DeviceType)) {
continue;
}
if (ConsoleDev->ConsoleId == (NewActivatedEngine + 1)) {
break;
}
}
if (Index >= mConsoleDevListCount) {
return EFI_SUCCESS;
}
//
// Change actived DE
//
FBSetActivedEngine (Private, NewActivatedEngine + 1);
for (Index = 0; Index < mConsoleDevListCount; Index++) {
ConsoleDev = mConsoleDevList[Index];
if (!IsConInDeviceType (ConsoleDev->DeviceType) || IsConOutDeviceType (ConsoleDev->DeviceType)) {
continue;
}
//
// Set ConsoleId to actived DE
//
ConsoleDev->ConsoleId = (H2O_CONSOLE_ID)(Private->ActivatedEngine + 1);
}
return EFI_SUCCESS;
}
FBNotifyEventToTarget (Private, Event);
return EFI_SUCCESS;
}
/**
Check if two strings are the same.
@param[in] String1 Pointer to string 1
@param[in] String2 Pointer to string 2
@retval TRUE Two strings are the same
@retval FALSE Two strings are not the same
**/
BOOLEAN
IsSameString (
IN CHAR16 *String1,
IN CHAR16 *String2
)
{
if ((String1 == NULL && String2 == NULL) ||
(String1 != NULL && String2 != NULL && StrCmp (String1, String2) == 0)) {
return TRUE;
}
return FALSE;
}
/**
Check if two images are the same.
@param[in] Image1 Pointer to image 1
@param[in] Image2 Pointer to image 2
@retval TRUE Two images are the same
@retval FALSE Two images are not the same
**/
BOOLEAN
IsSameImage (
IN EFI_IMAGE_INPUT *Image1,
IN EFI_IMAGE_INPUT *Image2
)
{
if ((Image1 == NULL && Image2 == NULL) ||
(Image1 != NULL && Image2 != NULL && (Image1->Height == Image2->Height &&
Image1->Width == Image2->Width))) {
return TRUE;
}
return FALSE;
}
/**
Check if two hot key info lists are the same.
@param[in] HotKeyInfo1Count Count of hot key info 1
@param[in] HotKeyInfo1 Pointer to hot key info 1
@param[in] HotKeyInfo2Count Count of hot key info 2
@param[in] HotKeyInfo2 Pointer to hot key info 2
@retval TRUE Two hot key info lists are the same
@retval FALSE Two hot key info lists are not the same
**/
STATIC
BOOLEAN
IsSameHotKeyInfo (
IN UINT32 HotKeyInfo1Count,
IN HOT_KEY_INFO *HotKeyInfo1,
IN UINT32 HotKeyInfo2Count,
IN HOT_KEY_INFO *HotKeyInfo2
)
{
UINT32 Index;
INTN Result;
EFI_STATUS Status;
if (HotKeyInfo1Count != HotKeyInfo2Count) {
return FALSE;
}
if (HotKeyInfo1Count != 0 && (HotKeyInfo1 == NULL || HotKeyInfo2 == NULL)) {
return FALSE;
}
for (Index = 0; Index < HotKeyInfo1Count; Index++, HotKeyInfo1++, HotKeyInfo2++) {
if ((HotKeyInfo1->HotKeyAction != HotKeyInfo2->HotKeyAction ) ||
(HotKeyInfo1->GroupId != HotKeyInfo2->GroupId ) ||
(HotKeyInfo1->Display != HotKeyInfo2->Display ) ||
(HotKeyInfo1->HotKeyDefaultId != HotKeyInfo2->HotKeyDefaultId ) ||
(HotKeyInfo1->HotKeyTargetFormId != HotKeyInfo2->HotKeyTargetFormId ) ||
(HotKeyInfo1->HotKeyTargetQuestionId != HotKeyInfo2->HotKeyTargetQuestionId ) ||
(CompareMem (&HotKeyInfo1->KeyData, &HotKeyInfo2->KeyData, sizeof(EFI_KEY_DATA)) != 0 ) ||
(!CompareGuid (&HotKeyInfo1->HotKeyTargetFormSetGuid, &HotKeyInfo2->HotKeyTargetFormSetGuid)) ||
!IsSameString (HotKeyInfo1->Mark, HotKeyInfo2->Mark) ||
!IsSameString (HotKeyInfo1->String, HotKeyInfo2->String) ||
!IsSameImage (HotKeyInfo1->ImageBuffer, HotKeyInfo2->ImageBuffer)) {
return FALSE;
}
Status = CompareValue (&HotKeyInfo1->HotKeyHiiValue, &HotKeyInfo2->HotKeyHiiValue, &Result, NULL);
if (EFI_ERROR(Status) || Result != 0) {
return FALSE;
}
}
return TRUE;
}
/**
Formbrowser select question
@param [in] Private Formbrowser private data
@param [in] Event Display engine event type
@retval Status Formbrowser select question status
**/
STATIC
EFI_STATUS
FBSelectQuestion (
IN H2O_FORM_BROWSER_PRIVATE_DATA *Private,
IN CONST H2O_DISPLAY_ENGINE_EVT *Event
)
{
EFI_STATUS Status;
H2O_DISPLAY_ENGINE_EVT_SELECT_Q *SelectQ;
FORM_BROWSER_FORM *Form;
FORM_BROWSER_STATEMENT *Statement;
FORM_DISPLAY_ENGINE_STATEMENT DisplayStatement;
UINT32 HotKeyInfoCount;
HOT_KEY_INFO *HotKeyInfo;
H2O_DISPLAY_ENGINE_EVT_OPEN_P OpenP;
SelectQ = (H2O_DISPLAY_ENGINE_EVT_SELECT_Q *)Event;
Form = FBPageIdToForm (Private, SelectQ->PageId);
if (Form == NULL) {
return EFI_NOT_FOUND;
}
if (SelectQ->QuestionId != 0) {
Statement = IdToQuestion2 (Form, SelectQ->QuestionId);
} else {
DisplayStatement.OpCode = SelectQ->IfrOpCode;
Statement = GetBrowserStatement (&DisplayStatement);
}
if (Statement == NULL) {
return EFI_NOT_FOUND;
}
//
// BUGBUG: Differenet page,
// need follow ProcessGotoOpCode to change formset, form, and question
//
ASSERT (SelectQ->PageId == Private->FB.CurrentP->PageId);
if (SelectQ->PageId != Private->FB.CurrentP->PageId) {
return EFI_NOT_FOUND;
}
Private->FB.CurrentQ = &Statement->Statement;
gCurrentSelection->Statement = Statement;
gCurrentSelection->QuestionId = Statement->QuestionId;
gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId;
mCurFakeQestId = (gCurrentSelection->CurrentMenu->QuestionId == 0) ? Statement->FakeQuestionId : 0;
Status = FBGetHotKeyInfo (
gCurrentSelection->FormSet,
gCurrentSelection->Form,
gCurrentSelection->Statement,
&HotKeyInfoCount,
&HotKeyInfo
);
if (!EFI_ERROR (Status)) {
if (IsSameHotKeyInfo (Private->NumberOfHotKeys, Private->HotKeyInfo, HotKeyInfoCount, HotKeyInfo)) {
DestroyHotKeyInfo (HotKeyInfoCount, HotKeyInfo);
} else {
DestroyHotKeyInfo (Private->NumberOfHotKeys, Private->HotKeyInfo);
Private->NumberOfHotKeys = HotKeyInfoCount;
Private->HotKeyInfo = HotKeyInfo;
gCurrentSelection->Form->PageInfo.HotKeyInfo = Private->HotKeyInfo;
//
// Refresh page because hot key list is changed.
//
ZeroMem (&OpenP, sizeof (H2O_DISPLAY_ENGINE_EVT_OPEN_P));
OpenP.Hdr.Size = sizeof (H2O_DISPLAY_ENGINE_EVT_OPEN_P);
OpenP.Hdr.Target = H2O_DISPLAY_ENGINE_EVT_TARGET_FORM_BROWSER;
OpenP.Hdr.Type = H2O_DISPLAY_ENGINE_EVT_TYPE_OPEN_P;
FBBroadcastEvent ((H2O_DISPLAY_ENGINE_EVT*)&OpenP);
}
}
Status = FBBroadcastEvent (Event);
return Status;
}
/**
Formbrowser timer refresh entry list
@param [in] Private Formbrowser private data
@param [in] Event Display engine event type
@retval EFI_SUCCESS Formbrowser timer refresh entry list success
**/
EFI_STATUS
FBTimer (
IN H2O_FORM_BROWSER_PRIVATE_DATA *Private,
IN CONST H2O_DISPLAY_ENGINE_EVT *Event
)
{
H2O_DISPLAY_ENGINE_EVT_TIMER *Timer;
H2O_DISPLAY_ENGINE_PROTOCOL *TargetDE;
Timer = (H2O_DISPLAY_ENGINE_EVT_TIMER *)Event;
ASSERT (Timer->Hdr.Target != H2O_DISPLAY_ENGINE_EVT_TARGET_BROADCAST);
//
//Not yet implement; it should send to DE
//
if (Timer->Hdr.Target != H2O_DISPLAY_ENGINE_EVT_TARGET_FORM_BROWSER) {
if (Event->Target > (INT32) Private->EngineListCount) {
return EFI_NOT_FOUND;
}
if (Private->EngineList[Event->Target - 1].AttachedConsoleCount != 0) {
TargetDE = Private->EngineList[Event->Target - 1].DisplayEngine;
TargetDE->Notify (TargetDE, Event);
}
return EFI_SUCCESS;
}
switch (Timer->TimerId) {
default:
ASSERT (FALSE);
}
return EFI_SUCCESS;
}
/**
Get current time in nano second
@return current time in nano second or 0 if get fail
**/
UINT64
EFIAPI
GetElapsedTimeInNanoSec (
VOID
)
{
EFI_STATUS Status;
STATIC EFI_CPU_ARCH_PROTOCOL *Cpu = NULL;
UINT64 CurrentTick;
UINT64 TimerPeriod;
STATIC UINT64 TimerPeriodInPs = 0; // 1e-12 second
if (Cpu == NULL) {
Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Cpu);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
return 0;
}
}
Status = Cpu->GetTimerValue (Cpu, 0, &CurrentTick, NULL);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "H2O form browser get tick fail\n"));
return 0;
}
if (TimerPeriodInPs == 0) {
Status = Cpu->GetTimerValue (Cpu, 0, &CurrentTick, &TimerPeriod);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "H2O form browser get tick fail\n"));
return 0;
}
TimerPeriodInPs = DivU64x32 (TimerPeriod, 1000);
}
return MultU64x32 (DivU64x32 (CurrentTick, 1000), (UINT32) TimerPeriodInPs);
}
/**
Formbrowser set timer.
@param [in] Target Target of killtimer
@param [in] TimerId A id to the function to be notified when the time-out value elapses
@param [in] Context Context of time event
@param [in] TriggerTime trigger time
@retval EFI_SUCCESS Formbrowser set timer successfully
**/
EFI_STATUS
FBSetTimer (
IN INT32 Target,
IN UINT32 TimerId,
IN H2O_FORM_BROWSER_TIMER_TYPE Type,
IN CONST H2O_DISPLAY_ENGINE_EVT *NotifyEvent,
IN UINT64 TimeoutInNanoSec
)
{
TIMERINFO *TimerInfo;
H2O_DISPLAY_ENGINE_EVT *Event;
LIST_ENTRY *Node;
if (NotifyEvent == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// check current timer lsit to avoid register timer repeatedly
//
Node = GetFirstNode (&mFBPrivate.TimerList);
while (!IsNull (&mFBPrivate.TimerList, Node)) {
TimerInfo = TIMERINFO_FROM_LINK (Node);
if ((TimerInfo->Target == Target) &&
(TimerInfo->TimerId == TimerId) &&
(TimerInfo->Type == Type) &&
(TimerInfo->TimeoutInNanoSec == TimeoutInNanoSec)) {
return EFI_SUCCESS;
}
Node = GetNextNode (&mFBPrivate.TimerList, Node);
}
TimerInfo = AllocateZeroPool (sizeof (TIMERINFO));
if (TimerInfo == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Event = AllocateCopyPool (NotifyEvent->Size, NotifyEvent);
if (Event == NULL) {
FreePool (TimerInfo);
return EFI_OUT_OF_RESOURCES;
}
TimerInfo->Signature = H2O_FORM_BROWSER_TIMER_INFO_SIGNATURE;
TimerInfo->Target = Target;
TimerInfo->TimerId = TimerId;
TimerInfo->Type = Type;
TimerInfo->NotifyEvent = Event;
TimerInfo->TimeoutInNanoSec = TimeoutInNanoSec;
TimerInfo->ClockExpiresInNanoSec = GetElapsedTimeInNanoSec () + TimeoutInNanoSec;
InsertTailList (&mFBPrivate.TimerList, &TimerInfo->Link);
return EFI_SUCCESS;
}
/**
Formbrowser kill timer.
@param [in] Target Target of killtimer
@param [in] TimerId A id to the function to be notified when the time-out value elapses
@retval TRUE Formbrowser kill timer success
@retval FALSE Formbrowser kill timer fail
**/
BOOLEAN
FBKillTimer (
IN INT32 Target,
IN UINT32 TimerId
)
{
LIST_ENTRY *Link;
H2O_FORM_BROWSER_PRIVATE_DATA *Private;
TIMERINFO *TimerInfo;
Private = &mFBPrivate;
Link = GetFirstNode (&Private->TimerList);
while (!IsNull (&Private->TimerList, Link)) {
TimerInfo = TIMERINFO_FROM_LINK (Link);
Link = GetNextNode (&Private->TimerList, Link);
if (TimerInfo->Target == Target && TimerInfo->TimerId == TimerId) {
RemoveEntryList (&TimerInfo->Link);
FreePool (TimerInfo->NotifyEvent);
FreePool (TimerInfo);
return TRUE;
}
}
return FALSE;
}
/**
Formbrowser broadcast event.
@param [in] Event Display engine event type
@retval Status Formbrowser broadcast event status
**/
EFI_STATUS
FBBroadcastEvent (
IN CONST H2O_DISPLAY_ENGINE_EVT *Event
)
{
EFI_STATUS Status;
H2O_FORM_BROWSER_PRIVATE_DATA *Private;
UINT32 Index;
Private = &mFBPrivate;
Status = EFI_SUCCESS;
for (Index = 0; Index < Private->EngineListCount; Index++) {
if (Private->EngineList[Index].AttachedConsoleCount != 0) {
Status = Private->EngineList[Index].DisplayEngine->Notify (Private->EngineList[Index].DisplayEngine, Event);
}
}
return Status;
}
/**
Queue of event.
@param [in] Event Display engine event type
@retval EFI_SUCCESS Queue of event success
**/
EFI_STATUS
QueueEvent (
H2O_DISPLAY_ENGINE_EVT *Event
)
{
H2O_FORM_BROWSER_PRIVATE_DATA *Private;
H2O_DISPLAY_ENGINE_EVENT_NODE *Node;
Private = &mFBPrivate;
Node = (H2O_DISPLAY_ENGINE_EVENT_NODE*)AllocateZeroPool (sizeof (H2O_DISPLAY_ENGINE_EVENT_NODE));
if (Node == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Node->Signature = H2O_DISPLAY_ENGINE_EVENT_NODE_SIGNATURE;
Node->Event = (H2O_DISPLAY_ENGINE_EVT *) AllocatePool (Event->Size);
if (Node->Event == NULL) {
return EFI_OUT_OF_RESOURCES;
}
CopyMem (Node->Event, Event, Event->Size);
EfiAcquireLock (&mEventQueueLock);
InsertTailList (&mEventQueue, &Node->Link);
EfiReleaseLock (&mEventQueueLock);
return EFI_SUCCESS;
}
/**
Get next queue event.
@param [in] Event Display engine event type
@retval EFI_SUCCESS Get next queue event successfully
**/
STATIC
BOOLEAN
GetNextQueuedEvent (
H2O_DISPLAY_ENGINE_EVT **Event
)
{
H2O_FORM_BROWSER_PRIVATE_DATA *Private;
H2O_DISPLAY_ENGINE_EVENT_NODE *Node;
Private = &mFBPrivate;
ASSERT (Event != NULL);
EfiAcquireLock (&mEventQueueLock);
if (IsListEmpty (&mEventQueue)) {
EfiReleaseLock (&mEventQueueLock);
return FALSE;
}
Node = H2O_DISPLAY_ENGINE_EVENT_NODE_FROM_LINK (
(LIST_ENTRY *)GetFirstNode (&mEventQueue)
);
RemoveEntryList (&Node->Link);
EfiReleaseLock (&mEventQueueLock);
*Event = Node->Event;
FreePool (Node);
return TRUE;
}
/**
Queue of event.
@param [in] NumberOfEvents Number Of events
@param [in] UserEvents Event list
@param [out] UserIndex Event index
@retval EFI_SUCCESS Queue of event success
**/
STATIC
EFI_STATUS
EFIAPI
FBWaitForEvent (
IN UINTN NumberOfEvents,
IN EFI_EVENT *UserEvents,
OUT UINTN *UserIndex
)
{
EFI_STATUS Status;
UINTN Index;
for (Index = 0; Index < NumberOfEvents; Index++) {
Status = gBS->CheckEvent (UserEvents[Index]);
//
// provide index of event that caused problem
//
if (!EFI_ERROR (Status)) {
*UserIndex = Index;
return Status;
}
}
return EFI_NOT_READY;
}
STATIC
EFI_STATUS
GetTargetInfo (
IN EFI_GUID *TargetFormSetGuid,
IN UINT16 TargetFormId,
IN UINT16 TargetQuestionId,
OUT FORM_BROWSER_FORMSET **TargetFormSet,
OUT FORM_BROWSER_FORM **TargetForm,
OUT FORM_BROWSER_STATEMENT **TargetStatement
)
{
FORM_BROWSER_FORMSET *FormSet;
FORM_BROWSER_FORM *Form;
FORM_BROWSER_STATEMENT *Statement;
LIST_ENTRY *LinkFormSet;
LIST_ENTRY *LinkForm;
LIST_ENTRY *LinkStatement;
if (TargetFormSetGuid == NULL || CompareGuid (TargetFormSetGuid, &gZeroGuid)) {
return EFI_NOT_FOUND;
}
LinkFormSet = GetFirstNode (&mFBPrivate.FormSetList);
while (!IsNull (&mFBPrivate.FormSetList, LinkFormSet)) {
FormSet = FORM_BROWSER_FORMSET_FROM_DISPLAY_LINK (LinkFormSet);
LinkFormSet = GetNextNode (&mFBPrivate.FormSetList, LinkFormSet);
if (!CompareGuid (&FormSet->Guid, TargetFormSetGuid)) {
continue;
}
if (TargetFormId == 0 && TargetQuestionId == 0) {
*TargetFormSet = FormSet;
*TargetForm = NULL;
*TargetStatement = NULL;
return EFI_SUCCESS;
}
LinkForm = GetFirstNode (&FormSet->FormListHead);
while (!IsNull (&FormSet->FormListHead, LinkForm)) {
Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm);
LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm);
if (TargetFormId != 0) {
if (Form->FormId == TargetFormId) {
if (TargetQuestionId == 0) {
*TargetFormSet = FormSet;
*TargetForm = Form;
*TargetStatement = NULL;
return EFI_SUCCESS;
}
} else {
continue;
}
}
LinkStatement = GetFirstNode (&Form->StatementListHead);
while (!IsNull (&Form->StatementListHead, LinkStatement)) {
Statement = FORM_BROWSER_STATEMENT_FROM_LINK (LinkStatement);
LinkStatement = GetNextNode (&Form->StatementListHead, LinkStatement);
if (Statement->QuestionId == TargetQuestionId) {
*TargetFormSet = FormSet;
*TargetForm = Form;
*TargetStatement = Statement;
return EFI_SUCCESS;
}
}
}
}
return EFI_NOT_FOUND;
}
EFI_STATUS
DiscardQuestion (
IN FORM_BROWSER_FORMSET *FormSet,
IN FORM_BROWSER_FORM *Form,
IN FORM_BROWSER_STATEMENT *Statement
)
{
if (FormSet == NULL || Form == NULL || Statement == NULL) {
return EFI_INVALID_PARAMETER;
}
if (Statement->ValueChanged) {
GetQuestionValue (FormSet, Form, Statement, GetSetValueWithBuffer);
SetQuestionValue (FormSet, Form, Statement, GetSetValueWithEditBuffer);
IsQuestionValueChanged(FormSet, Form, Statement, GetSetValueWithBuffer);
}
return EFI_SUCCESS;
}
EFI_STATUS
LoadQuestionDefault (
IN FORM_BROWSER_FORMSET *FormSet,
IN FORM_BROWSER_FORM *Form,
IN FORM_BROWSER_STATEMENT *Statement,
IN UINT16 DefaultId
)
{
EFI_STATUS Status;
if (FormSet == NULL || Form == NULL || Statement == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = GetQuestionDefault (FormSet, Form, Statement, DefaultId);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Synchronize Buffer storage's Edit buffer
//
if ((Statement->Storage != NULL) &&
(Statement->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {
SetQuestionValue (FormSet, Form, Statement, GetSetValueWithEditBuffer);
}
IsQuestionValueChanged(FormSet, Form, Statement, GetSetValueWithBuffer);
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
SubmitQuestion (
IN FORM_BROWSER_STATEMENT *Statement
)
{
EFI_STATUS Status;
CHAR16 *ConfigRequest;
EFI_STRING ConfigResp;
EFI_STRING Progress;
if (Statement == NULL) {
return EFI_INVALID_PARAMETER;
}
if (Statement->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE ||
Statement->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
return EFI_UNSUPPORTED;
}
//
// 1. Prepare <ConfigResp>
//
ConfigRequest = CatSPrint (NULL, L"%s%s", Statement->Storage->ConfigHdr, Statement->BlockName);
if (ConfigRequest == NULL) {
return EFI_UNSUPPORTED;
}
Status = StorageToConfigResp (Statement->Storage, &ConfigResp, ConfigRequest, TRUE);
FreePool (ConfigRequest);
if (EFI_ERROR (Status)) {
return Status;
}
//
// 2. Set value to hii config routine protocol.
//
Status = FBCallRouteConfigFn (ConfigResp, &Progress);
FreePool (ConfigResp);
if (EFI_ERROR (Status)) {
return Status;
}
//
// 3. Config success, update storage shadow Buffer
//
if (Statement->Storage->Type == EFI_HII_VARSTORE_BUFFER ||
Statement->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
CopyMem (
Statement->Storage->Buffer + Statement->VarStoreInfo.VarOffset,
Statement->Storage->EditBuffer + Statement->VarStoreInfo.VarOffset,
Statement->StorageWidth
);
//} else if (Statement->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
}
//
// 4. Update the NV flag.
//
if (Statement->ValueChanged && ((Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0)) {
gResetRequired = TRUE;
}
if (Statement->ValueChanged) {
Statement->ValueChanged = FALSE;
}
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
FBHotKeyDiscard (
IN H2O_DISPLAY_ENGINE_EVT_HOT_KEY *HotKeyEvent
)
{
EFI_STATUS Status;
FORM_BROWSER_FORMSET *FormSet;
FORM_BROWSER_FORM *Form;
FORM_BROWSER_STATEMENT *Statement;
if (HotKeyEvent == NULL) {
return EFI_INVALID_PARAMETER;
}
if (CompareGuid (&HotKeyEvent->HotKeyTargetFormSetGuid, &gZeroGuid)) {
return DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
}
Status = GetTargetInfo (
&HotKeyEvent->HotKeyTargetFormSetGuid,
HotKeyEvent->HotKeyTargetFormId,
HotKeyEvent->HotKeyTargetQuestionId,
&FormSet,
&Form,
&Statement
);
if (EFI_ERROR (Status)) {
return Status;
}
if (HotKeyEvent->HotKeyTargetFormId == 0 && HotKeyEvent->HotKeyTargetQuestionId == 0) {
return DiscardForm (FormSet, NULL, FormSetLevel);
} else if (HotKeyEvent->HotKeyTargetFormId != 0 && HotKeyEvent->HotKeyTargetQuestionId == 0) {
return DiscardForm (FormSet, Form, FormLevel);
} else {
return DiscardQuestion (FormSet, Form, Statement);
}
}
STATIC
EFI_STATUS
FBHotKeyLoadDefault (
IN H2O_DISPLAY_ENGINE_EVT_HOT_KEY *HotKeyEvent
)
{
EFI_STATUS Status;
FORM_BROWSER_FORMSET *FormSet;
FORM_BROWSER_FORM *Form;
FORM_BROWSER_STATEMENT *Statement;
if (HotKeyEvent == NULL) {
return EFI_INVALID_PARAMETER;
}
if (CompareGuid (&HotKeyEvent->HotKeyTargetFormSetGuid, &gZeroGuid)) {
if (GetScuFormset () != NULL) {
Status = BroadcastOpenDByHotKeyEvt (H2O_DISPLAY_ENGINE_EVT_TYPE_DEFAULT);
if (EFI_ERROR (Status)) {
return Status;
}
}
Status = ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, HotKeyEvent->HotKeyDefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE);
UpdateStatementStatus (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
return Status;
}
Status = GetTargetInfo (
&HotKeyEvent->HotKeyTargetFormSetGuid,
HotKeyEvent->HotKeyTargetFormId,
HotKeyEvent->HotKeyTargetQuestionId,
&FormSet,
&Form,
&Statement
);
if (EFI_ERROR (Status)) {
return Status;
}
if (HotKeyEvent->HotKeyTargetFormId == 0 && HotKeyEvent->HotKeyTargetQuestionId == 0) {
Status = ExtractDefault (FormSet, NULL, HotKeyEvent->HotKeyDefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE, FALSE);
UpdateStatementStatus (FormSet, NULL, FormSetLevel);
return Status;
} else if (HotKeyEvent->HotKeyTargetFormId != 0 && HotKeyEvent->HotKeyTargetQuestionId == 0) {
Status = ExtractDefault (FormSet, Form, HotKeyEvent->HotKeyDefaultId, FormLevel, GetDefaultForAll, NULL, FALSE, FALSE);
UpdateStatementStatus (FormSet, Form, FormLevel);
return Status;
} else {
return LoadQuestionDefault (FormSet, Form, Statement, HotKeyEvent->HotKeyDefaultId);
}
}
STATIC
EFI_STATUS
FBHotKeySave (
IN H2O_DISPLAY_ENGINE_EVT_HOT_KEY *HotKeyEvent
)
{
EFI_STATUS Status;
FORM_BROWSER_FORMSET *FormSet;
FORM_BROWSER_FORM *Form;
FORM_BROWSER_STATEMENT *Statement;
USER_INPUT *OrgUserInputData;
if (HotKeyEvent == NULL) {
return EFI_INVALID_PARAMETER;
}
if (CompareGuid (&HotKeyEvent->HotKeyTargetFormSetGuid, &gZeroGuid)) {
OrgUserInputData = gUserInput;
Status = SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
gUserInput = OrgUserInputData;
return Status;
}
Status = GetTargetInfo (
&HotKeyEvent->HotKeyTargetFormSetGuid,
HotKeyEvent->HotKeyTargetFormId,
HotKeyEvent->HotKeyTargetQuestionId,
&FormSet,
&Form,
&Statement
);
if (EFI_ERROR (Status)) {
return Status;
}
OrgUserInputData = gUserInput;
if (HotKeyEvent->HotKeyTargetFormId == 0 && HotKeyEvent->HotKeyTargetQuestionId == 0) {
Status = SubmitForm (FormSet, NULL, FormSetLevel);
} else if (HotKeyEvent->HotKeyTargetFormId != 0 && HotKeyEvent->HotKeyTargetQuestionId == 0) {
Status = SubmitForm (FormSet, Form, FormLevel);
} else {
Status = SubmitQuestion (Statement);
}
gUserInput = OrgUserInputData;
return Status;
}
STATIC
EFI_STATUS
FBHotKeyGoTo (
IN H2O_DISPLAY_ENGINE_EVT_HOT_KEY *HotKeyEvent
)
{
FORM_BROWSER_STATEMENT Statement;
if (HotKeyEvent == NULL) {
return EFI_INVALID_PARAMETER;
}
ZeroMem (&Statement, sizeof (FORM_BROWSER_STATEMENT));
CopyGuid (&Statement.HiiValue.Value.ref.FormSetGuid, &HotKeyEvent->HotKeyTargetFormSetGuid);
Statement.HiiValue.Value.ref.FormId = HotKeyEvent->HotKeyTargetFormId;
Statement.HiiValue.Value.ref.QuestionId = HotKeyEvent->HotKeyTargetQuestionId;
return ProcessGotoOpCode (&Statement, gCurrentSelection);
}
STATIC
EFI_STATUS
FBHotKeyCallback (
IN H2O_DISPLAY_ENGINE_EVT_HOT_KEY *HotKeyEvent
)
{
EFI_HII_HANDLE HiiHandle;
EFI_STATUS Status;
EFI_HANDLE DriverHandle;
EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
EFI_BROWSER_ACTION_REQUEST ActionRequest;
UINT16 QuestionId;
FORM_BROWSER_STATEMENT *Statement;
EFI_GUID *FormsetGuid;
UINT16 FormId;
EFI_HII_HANDLE OrgHiiHandle;
if (HotKeyEvent == NULL) {
return EFI_INVALID_PARAMETER;
}
OrgHiiHandle = mSystemLevelFormSet->HiiHandle;
if (CompareGuid (&HotKeyEvent->HotKeyTargetFormSetGuid, &gZeroGuid)) {
HiiHandle = gCurrentSelection->Handle;
FormsetGuid = &gCurrentSelection->FormSetGuid;
} else {
HiiHandle = FormSetGuidToHiiHandle (&HotKeyEvent->HotKeyTargetFormSetGuid);
FormsetGuid = &HotKeyEvent->HotKeyTargetFormSetGuid;
}
FormId = (HotKeyEvent->HotKeyTargetFormId == 0) ? gCurrentSelection->FormId : HotKeyEvent->HotKeyTargetFormId;
if (HotKeyEvent->HotKeyTargetQuestionId == 0) {
if (mFBPrivate.FB.CurrentQ == NULL) {
return EFI_NOT_FOUND;
}
QuestionId = mFBPrivate.FB.CurrentQ->QuestionId;
Statement = FORM_BROWSER_STATEMENT_FROM_H2O_STATEMENT(mFBPrivate.FB.CurrentQ);
if (IS_IMPORT_STATEMENT (Statement)) {
QuestionId = Statement->ImportInfo->SrcStatement->QuestionId;
if (CompareGuid (&HotKeyEvent->HotKeyTargetFormSetGuid, &gZeroGuid)) {
HiiHandle = Statement->ImportInfo->SrcFormSet->HiiHandle;
FormsetGuid = &Statement->ImportInfo->SrcFormSet->Guid;
mSystemLevelFormSet->HiiHandle = HiiHandle;
}
if (HotKeyEvent->HotKeyTargetFormId == 0) {
FormId = Statement->ImportInfo->SrcForm->FormId;
}
}
} else {
QuestionId = HotKeyEvent->HotKeyTargetQuestionId;
}
Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, HiiHandle, &DriverHandle);
if (EFI_ERROR (Status)) {
goto Exit;
}
Status = gBS->HandleProtocol (DriverHandle, &gEfiHiiConfigAccessProtocolGuid, (VOID **) &ConfigAccess);
if (EFI_ERROR (Status)) {
goto Exit;
}
Status = FBCallCallbackFn (
ConfigAccess,
H2O_BROWSER_ACTION_HOT_KEY_CALLBACK,
QuestionId,
HotKeyEvent->HotKeyHiiValue.Type,
(HotKeyEvent->HotKeyHiiValue.Type == EFI_IFR_TYPE_BUFFER) ? HotKeyEvent->HotKeyHiiValue.BufferLen : sizeof (EFI_IFR_TYPE_VALUE),
&HotKeyEvent->HotKeyHiiValue.Value,
&ActionRequest,
FormsetGuid,
FormId
);
Exit:
mSystemLevelFormSet->HiiHandle = OrgHiiHandle;
return Status;
}
STATIC
EFI_STATUS
FBHotKeySetQuestionValue (
IN H2O_DISPLAY_ENGINE_EVT_HOT_KEY *HotKeyEvent
)
{
EFI_STATUS Status;
FORM_BROWSER_FORMSET *FormSet;
FORM_BROWSER_FORM *Form;
FORM_BROWSER_STATEMENT *Statement;
UINTN StringLength;
FORM_BROWSER_FORMSET *BackupFormSet;
FORM_BROWSER_FORM *BackupForm;
UINTN Index;
if (HotKeyEvent == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = GetTargetInfo (
&HotKeyEvent->HotKeyTargetFormSetGuid,
HotKeyEvent->HotKeyTargetFormId,
HotKeyEvent->HotKeyTargetQuestionId,
&FormSet,
&Form,
&Statement
);
if (EFI_ERROR (Status) || Statement == NULL) {
return Status;
}
if (!Statement->Statement.Selectable) {
return EFI_ABORTED;
}
switch (Statement->Operand) {
case EFI_IFR_STRING_OP:
if (HotKeyEvent->HotKeyHiiValue.Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
StringLength = StrLen ((CHAR16 *) HotKeyEvent->HotKeyHiiValue.Buffer);
if (StringLength < Statement->Minimum || StringLength > Statement->Maximum) {
return EFI_ABORTED;
}
HiiSetString (FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16 *) HotKeyEvent->HotKeyHiiValue.Buffer, NULL);
CopyMem (Statement->BufferValue, HotKeyEvent->HotKeyHiiValue.Buffer, (StringLength + 1) * sizeof (CHAR16));
break;
case EFI_IFR_PASSWORD_OP:
if (HotKeyEvent->HotKeyHiiValue.Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
StringLength = StrLen ((CHAR16 *) HotKeyEvent->HotKeyHiiValue.Buffer);
if (StringLength != 0 && (StringLength < Statement->Minimum || StringLength > Statement->Maximum)) {
return EFI_ABORTED;
}
HiiSetString (FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16 *) HotKeyEvent->HotKeyHiiValue.Buffer, NULL);
CopyMem (Statement->BufferValue, HotKeyEvent->HotKeyHiiValue.Buffer, (StringLength + 1) * sizeof (CHAR16));
//
// Two password match, send it to Configuration Driver
//
if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
BackupFormSet = gCurrentSelection->FormSet;
BackupForm = gCurrentSelection->Form;
gCurrentSelection->FormSet = FormSet;
gCurrentSelection->Form = Form;
mDisplayStatement.OpCode = Statement->OpCode;
Status = PasswordCheck (NULL, &mDisplayStatement, (CHAR16 *) Statement->BufferValue);
ShowPwdStatusMessage (0, Status);
gCurrentSelection->FormSet = BackupFormSet;
gCurrentSelection->Form = BackupForm;
//
// Clean the value after saved it.
//
ZeroMem (Statement->BufferValue, (StringLength + 1) * sizeof (CHAR16));
HiiSetString (FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16*) Statement->BufferValue, NULL);
} else {
SetQuestionValue (FormSet, Form, Statement, GetSetValueWithHiiDriver);
}
break;
case EFI_IFR_ORDERED_LIST_OP:
if (HotKeyEvent->HotKeyHiiValue.Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
if (HotKeyEvent->HotKeyHiiValue.BufferLen > Statement->StorageWidth) {
return EFI_ABORTED;
}
CopyMem (Statement->BufferValue, HotKeyEvent->HotKeyHiiValue.Buffer, HotKeyEvent->HotKeyHiiValue.BufferLen);
break;
case EFI_IFR_NUMERIC_OP:
if (HotKeyEvent->HotKeyHiiValue.Value.u64 > Statement->Maximum ||
HotKeyEvent->HotKeyHiiValue.Value.u64 < Statement->Minimum) {
return EFI_ABORTED;
}
CopyMem (&Statement->HiiValue, &HotKeyEvent->HotKeyHiiValue, sizeof (EFI_HII_VALUE));
break;
case EFI_IFR_ONE_OF_OP:
for (Index = 0; Index < Statement->Statement.NumberOfOptions; Index++) {
if (HotKeyEvent->HotKeyHiiValue.Value.u64 == Statement->Statement.Options[Index].HiiValue.Value.u64) {
break;
}
}
if (Index == Statement->Statement.NumberOfOptions) {
return EFI_ABORTED;
}
CopyMem (&Statement->HiiValue, &HotKeyEvent->HotKeyHiiValue, sizeof (EFI_HII_VALUE));
break;
default:
CopyMem (&Statement->HiiValue, &HotKeyEvent->HotKeyHiiValue, sizeof (EFI_HII_VALUE));
break;
}
//
// Do the question validation.
//
Status = ValueChangedValidation (FormSet, Form, Statement);
if (!EFI_ERROR (Status) && (Statement->Operand != EFI_IFR_PASSWORD_OP)) {
SetQuestionValue (FormSet, Form, Statement, GetSetValueWithEditBuffer);
//
// Verify whether question value has checked, update the ValueChanged flag in Question.
//
IsQuestionValueChanged(FormSet, Form, Statement, GetSetValueWithBuffer);
}
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
FBHotKey (
IN CONST H2O_DISPLAY_ENGINE_EVT *Event,
OUT BOOLEAN *ExitFlag
)
{
EFI_STATUS Status;
H2O_DISPLAY_ENGINE_EVT_HOT_KEY *HotKeyEvent;
HotKeyEvent = (H2O_DISPLAY_ENGINE_EVT_HOT_KEY *) Event;
switch (HotKeyEvent->HotKeyAction) {
case HotKeyDiscard:
Status = FBHotKeyDiscard (HotKeyEvent);
if (EFI_ERROR (Status)) {
return Status;
}
gUserInput->Action = BROWSER_ACTION_NONE;
*ExitFlag = TRUE;
break;
case HotKeyLoadDefault:
Status = FBHotKeyLoadDefault (HotKeyEvent);
if (EFI_ERROR (Status)) {
return Status;
}
gUserInput->Action = BROWSER_ACTION_NONE;
*ExitFlag = TRUE;
break;
case HotKeySave:
Status = FBHotKeySave (HotKeyEvent);
if (EFI_ERROR (Status)) {
return Status;
}
gUserInput->Action = BROWSER_ACTION_NONE;
*ExitFlag = TRUE;
break;
case HotKeyGoTo:
Status = FBHotKeyGoTo (HotKeyEvent);
if (EFI_ERROR (Status)) {
return Status;
}
if (gCurrentSelection->Action == UI_ACTION_REFRESH_FORM &&
gCurrentSelection->FormId == gCurrentSelection->CurrentMenu->FormId) {
gCurrentSelection->CurrentMenu->QuestionId = gCurrentSelection->QuestionId;
}
gUserInput->Action = BROWSER_ACTION_GOTO;
*ExitFlag = TRUE;
break;
case HotKeyCallback:
Status = FBHotKeyCallback (HotKeyEvent);
if (EFI_ERROR (Status)) {
return Status;
}
mRefreshForm = TRUE;
break;
case HotKeySetQuestionValue:
Status = FBHotKeySetQuestionValue (HotKeyEvent);
if (EFI_ERROR (Status)) {
return Status;
}
gCurrentSelection->Action = UI_ACTION_REFRESH_FORM;
gUserInput->Action = BROWSER_ACTION_NONE;
*ExitFlag = TRUE;
break;
default:
Status = EFI_UNSUPPORTED;
break;
}
return Status;
}
BOOLEAN
IsValidKey (
IN EFI_INPUT_KEY *Key
)
{
if (Key == NULL) {
return FALSE;
}
if (Key->UnicodeChar == CHAR_LINEFEED &&
Key->ScanCode == SCAN_NULL) {
return FALSE;
}
return TRUE;
}
/**
Get next event according to device type.
@param [in] Event Display engine event type
@retval TRUE Get next event success
@retval FALSE Get next event fail
**/
STATIC
BOOLEAN
GetNextEventTimeout (
H2O_DISPLAY_ENGINE_EVT **Event,
UINTN TimeOut
)
{
EFI_STATUS Status;
UINTN Index;
EFI_INPUT_KEY Key;
EFI_KEY_DATA KeyData;
EFI_SIMPLE_POINTER_STATE MouseState;
H2O_DISPLAY_ENGINE_EVT_KEYPRESS *KeyEvent;
H2O_DISPLAY_ENGINE_EVT_REL_PTR_MOVE *MouseEvent;
H2O_DISPLAY_ENGINE_EVT_ABS_PTR_MOVE *AbsPtrEvent;
H2O_FORM_BROWSER_PRIVATE_DATA *Private;
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextIn;
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx;
EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer;
H2O_INPUT_EVENT_DESCRIPTION *InputEventDesc;
UINTN X;
UINTN Y;
BOOLEAN LeftButton;
BOOLEAN RightButton;
Private = &mFBPrivate;
if (Private->SetupMouse != NULL) {
Status = Private->SetupMouse->QueryState (Private->SetupMouse, &X, &Y, &LeftButton, &RightButton);
if (!EFI_ERROR (Status)) {
AbsPtrEvent = (H2O_DISPLAY_ENGINE_EVT_ABS_PTR_MOVE *)AllocateZeroPool (sizeof (H2O_DISPLAY_ENGINE_EVT_ABS_PTR_MOVE));
if (AbsPtrEvent == NULL) {
return FALSE;
}
AbsPtrEvent->Hdr.Size = sizeof (H2O_DISPLAY_ENGINE_EVT_ABS_PTR_MOVE);
AbsPtrEvent->Hdr.Type = H2O_DISPLAY_ENGINE_EVT_TYPE_ABS_PTR_MOVE;
//
// Set Target to actived DE
//
AbsPtrEvent->Hdr.Target = Private->SetupMouseConsoleId;
AbsPtrEvent->AbsPtrState.CurrentX = (UINT64)(X);
AbsPtrEvent->AbsPtrState.CurrentY = (UINT64)(Y);
if (LeftButton) {
AbsPtrEvent->AbsPtrState.ActiveButtons |= EFI_ABSP_TouchActive;
}
if (RightButton) {
AbsPtrEvent->AbsPtrState.ActiveButtons |= EFI_ABS_AltActive;
}
*Event = (H2O_DISPLAY_ENGINE_EVT*) AbsPtrEvent;
return TRUE;
}
}
if (mInputEventListCount == 0) {
return FALSE;
}
Index = 0;
Status = FBWaitForEvent (
(UINTN)mInputEventListCount,
mInputEventList,
&Index
);
if (EFI_ERROR (Status)) {
return FALSE;
}
InputEventDesc = &mInputEventDescList[Index];
switch (InputEventDesc->DeviceType) {
case H2O_FORM_BROWSER_CONSOLE_STI:
SimpleTextIn = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL*)InputEventDesc->Protocol;
Status = SimpleTextIn->ReadKeyStroke (SimpleTextIn, &Key);
if (EFI_ERROR (Status) || !IsValidKey (&Key)) {
return FALSE;
}
KeyEvent = (H2O_DISPLAY_ENGINE_EVT_KEYPRESS *)AllocateZeroPool (sizeof (H2O_DISPLAY_ENGINE_EVT_KEYPRESS));
if (KeyEvent == NULL) {
return FALSE;
}
KeyEvent->Hdr.Size = sizeof (H2O_DISPLAY_ENGINE_EVT_KEYPRESS);
KeyEvent->Hdr.Type = H2O_DISPLAY_ENGINE_EVT_TYPE_KEYPRESS;
KeyEvent->Hdr.Target = InputEventDesc->ConDev->ConsoleId;
CopyMem (&KeyEvent->KeyData.Key, &Key, sizeof (EFI_INPUT_KEY));
*Event = (H2O_DISPLAY_ENGINE_EVT*)KeyEvent;
break;
case H2O_FORM_BROWSER_CONSOLE_STI2:
SimpleTextInEx = (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL*)InputEventDesc->Protocol;
Status = SimpleTextInEx->ReadKeyStrokeEx (SimpleTextInEx, &KeyData);
if (EFI_ERROR (Status) || !IsValidKey (&KeyData.Key)) {
return FALSE;
}
KeyEvent = (H2O_DISPLAY_ENGINE_EVT_KEYPRESS *)AllocateZeroPool (sizeof (H2O_DISPLAY_ENGINE_EVT_KEYPRESS));
if (KeyEvent == NULL) {
return FALSE;
}
KeyEvent->Hdr.Size = sizeof (H2O_DISPLAY_ENGINE_EVT_KEYPRESS);
KeyEvent->Hdr.Type = H2O_DISPLAY_ENGINE_EVT_TYPE_KEYPRESS;
KeyEvent->Hdr.Target = InputEventDesc->ConDev->ConsoleId;
CopyMem (&KeyEvent->KeyData, &KeyData, sizeof (EFI_KEY_DATA));
*Event = (H2O_DISPLAY_ENGINE_EVT*)KeyEvent;
break;
case H2O_FORM_BROWSER_CONSOLE_SP:
SimplePointer = (EFI_SIMPLE_POINTER_PROTOCOL*)InputEventDesc->Protocol;
Status = SimplePointer->GetState (SimplePointer, &MouseState);
if (EFI_ERROR (Status)) {
return FALSE;
}
MouseEvent = (H2O_DISPLAY_ENGINE_EVT_REL_PTR_MOVE *)AllocateZeroPool (sizeof (H2O_DISPLAY_ENGINE_EVT_REL_PTR_MOVE));
if (MouseEvent == NULL) {
return FALSE;
}
MouseEvent->Hdr.Size = sizeof (H2O_DISPLAY_ENGINE_EVT_REL_PTR_MOVE);
MouseEvent->Hdr.Type = H2O_DISPLAY_ENGINE_EVT_TYPE_REL_PTR_MOVE;
MouseEvent->Hdr.Target = InputEventDesc->ConDev->ConsoleId;
CopyMem (&MouseEvent->State, &MouseState, sizeof (EFI_SIMPLE_POINTER_STATE));
*Event = (H2O_DISPLAY_ENGINE_EVT*)MouseEvent;
break;
default:
ASSERT (FALSE);
return FALSE;
}
return TRUE;
}
/**
Check timer event function.
If expired time came, add the notify event in queue.
**/
VOID
CheckTimerEvent (
VOID
)
{
LIST_ENTRY *StartLink;
LIST_ENTRY *CurrentLink;
TIMERINFO *TimerInfo;
if (IsListEmpty (&mFBPrivate.TimerList)) {
return;
}
StartLink = &mFBPrivate.TimerList;
CurrentLink = StartLink->ForwardLink;
while (CurrentLink != StartLink) {
TimerInfo = TIMERINFO_FROM_LINK (CurrentLink);
CurrentLink = CurrentLink->ForwardLink;
if (GetElapsedTimeInNanoSec () >= TimerInfo->ClockExpiresInNanoSec) {
QueueEvent (TimerInfo->NotifyEvent);
if (TimerInfo->Type != H2O_FORM_BROWSER_TIMER_TYPE_PERIODIC) {
FBKillTimer (TimerInfo->Target, TimerInfo->TimerId);
} else {
TimerInfo->ClockExpiresInNanoSec = GetElapsedTimeInNanoSec () + TimerInfo->TimeoutInNanoSec;
}
}
}
}
/**
Get next event.
@param [in] Event Display engine event type
@retval TRUE Get next event success
@retval FALSE Get next event fail
**/
BOOLEAN
GetNextEvent (
IN H2O_DISPLAY_ENGINE_EVT **Event
)
{
ASSERT (Event != NULL);
FBHotPlugEventFunc ();
if (GetNextQueuedEvent (Event)) {
return TRUE;
}
if (GetNextEventTimeout (Event, 0L)) {
if (FeaturePcdGet (PcdH2OBdsCpFormBrowserUserInputSupported)) {
TriggerCpFormBrowserUserInput (Event);
}
if (*Event != NULL) {
return TRUE;
}
}
CheckTimerEvent ();
return FALSE;
}
/**
Destroy event queue.
@param [in] Private Formbrowser private data
**/
VOID
DestroyEventQueue (
IN H2O_FORM_BROWSER_PRIVATE_DATA *Private
)
{
H2O_DISPLAY_ENGINE_EVT *Event;
BOOLEAN IsEmpty;
for (;;) {
EfiAcquireLock (&mEventQueueLock);
IsEmpty = IsListEmpty (&mEventQueue);
EfiReleaseLock (&mEventQueueLock);
if (IsEmpty) {
break;
}
GetNextQueuedEvent (&Event);
FreePool (Event);
}
}
/**
Convert event type to string.
@param [in] Event Display engine event type
@return Event string Get Event string
**/
CHAR16 *EventToStr(IN CONST H2O_EVT_TYPE EvtType)
{
#ifdef _MSC_VER
#define EVENTSTR(x) if(EvtType==x) return (L#x)
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_KEYPRESS);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_REL_PTR_MOVE);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_ABS_PTR_MOVE);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_TIMER);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_OPEN_L);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_SHUT_L);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_OPEN_P);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_SHUT_P);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_OPEN_Q);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_SHUT_Q);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_REFRESH);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_REFRESH_Q);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_SELECT_Q);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_SELECT_P);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_CHANGING_Q);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_CHANGE_Q);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_DEFAULT);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_DEFAULT_Q);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_DEFAULT_P);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_EXIT);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_SUBMIT_EXIT);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_DISCARD_EXIT);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_EXIT_P);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_SUBMIT_EXIT_P);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_DISCARD_EXIT_P);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_SUBMIT_P);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_DISCARD_P);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_OPEN_D);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_SHUT_D);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_TIMER);
EVENTSTR(H2O_DISPLAY_ENGINE_EVT_TYPE_SHOW_HELP);
#endif
return L"Unknown";
}
/**
Formbrowser event callback function.
@param [in] Event Display engine event type
@retval Status Formbrowser event callback function status
**/
EFI_STATUS
FBEventCallback (
IN CONST H2O_DISPLAY_ENGINE_EVT *Event,
OUT BOOLEAN *ExitFlag
)
{
H2O_FORM_BROWSER_PRIVATE_DATA *Private;
EFI_STATUS Status;
H2O_DISPLAY_ENGINE_EVT_CHANGE_Q *ChangeQ;
H2O_DISPLAY_ENGINE_EVT_SELECT_P *SelectP;
UINT16 HiiHandleIndex;
UINT16 FormId;
UINT8 Operand;
FORM_BROWSER_STATEMENT *Statement;
FORM_ENTRY_INFO *MenuList;
UINT32 Request;
BOOLEAN ShowSubmitDialog;
SETUP_DATE_CHANGE SetupDateChange;
Private = &mFBPrivate;
*ExitFlag = FALSE;
if (Event == NULL) {
return EFI_INVALID_PARAMETER;
}
ZeroMem (gUserInput, sizeof (USER_INPUT));
Status = EFI_SUCCESS;
switch (Event->Type) {
case H2O_DISPLAY_ENGINE_EVT_TYPE_KEYPRESS:
Status = FBKeyPress (Private, Event);
break;
case H2O_DISPLAY_ENGINE_EVT_TYPE_REL_PTR_MOVE:
case H2O_DISPLAY_ENGINE_EVT_TYPE_ABS_PTR_MOVE:
Status = FBNotifyEventToTarget (Private, Event);
break;
case H2O_DISPLAY_ENGINE_EVT_TYPE_OPEN_L:
case H2O_DISPLAY_ENGINE_EVT_TYPE_SHUT_L:
case H2O_DISPLAY_ENGINE_EVT_TYPE_OPEN_P:
case H2O_DISPLAY_ENGINE_EVT_TYPE_SHUT_P:
case H2O_DISPLAY_ENGINE_EVT_TYPE_REFRESH_Q:
case H2O_DISPLAY_ENGINE_EVT_TYPE_OPEN_D:
case H2O_DISPLAY_ENGINE_EVT_TYPE_SHUT_D:
case H2O_DISPLAY_ENGINE_EVT_TYPE_CHANGING_Q:
case H2O_DISPLAY_ENGINE_EVT_TYPE_SHUT_Q:
case H2O_DISPLAY_ENGINE_EVT_TYPE_REFRESH:
Status = FBBroadcastEvent (Event);
break;
case H2O_DISPLAY_ENGINE_EVT_TYPE_OPEN_Q:
Operand = Private->FB.CurrentQ->Operand;
if (Operand == EFI_IFR_REF_OP ||
Operand == EFI_IFR_ACTION_OP ||
Operand == EFI_IFR_RESET_BUTTON_OP) {
mDisplayStatement.OpCode = Private->FB.CurrentQ->IfrOpCode;
gUserInput->SelectedStatement = &mDisplayStatement;
*ExitFlag = TRUE;
} else if (Operand != EFI_IFR_CHECKBOX_OP) {
//
// Process checkbox in ChangeQ directly, not OpenQ
//
BroadcastOpenDByQ (Private->FB.CurrentQ);
}
break;
case H2O_DISPLAY_ENGINE_EVT_TYPE_CHANGE_Q:
if (Private->FB.CurrentQ == NULL || !Private->FB.CurrentQ->Selectable) {
break;
}
ChangeQ = (H2O_DISPLAY_ENGINE_EVT_CHANGE_Q *) Event;
mDisplayStatement.OpCode = Private->FB.CurrentQ->IfrOpCode;
gUserInput->SelectedStatement = &mDisplayStatement;
CopyHiiValue (&gUserInput->InputValue, &ChangeQ->HiiValue);
Statement = GetBrowserStatement(gUserInput->SelectedStatement);
if (Statement != NULL && (Statement->Operand == EFI_IFR_STRING_OP || Statement->Operand == EFI_IFR_PASSWORD_OP)) {
gUserInput->InputValue.Value.string = NewString ((EFI_STRING) ChangeQ->HiiValue.Buffer, gCurrentSelection->FormSet->HiiHandle);
}
*ExitFlag = TRUE;
break;
case H2O_DISPLAY_ENGINE_EVT_TYPE_SELECT_Q:
Status = FBSelectQuestion (Private, Event);
break;
case H2O_DISPLAY_ENGINE_EVT_TYPE_SELECT_P:
SelectP = (H2O_DISPLAY_ENGINE_EVT_SELECT_P *) Event;
HiiHandleIndex = (UINT16) (SelectP->PageId >> 16);
FormId = (UINT16) (SelectP->PageId & 0xFFFF);
if (HiiHandleIndex > Private->HiiHandleCount) {
break;
}
if (HiiHandleIndex == Private->HiiHandleIndex) {
if (FormId == gCurrentSelection->FormId) {
//
// do nothing
//
break;
}
gCurrentSelection->FormId = FormId;
gCurrentSelection->QuestionId = 0;
gCurrentSelection->Action = UI_ACTION_REFRESH_FORM;
} else {
Private->HiiHandleIndex = (UINTN) HiiHandleIndex;
gCurrentSelection->Handle = Private->HiiHandleList[Private->HiiHandleIndex];
gCurrentSelection->FormId = FormId;
gCurrentSelection->QuestionId = 0;
gCurrentSelection->CurrentMenu = NULL;
gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
CopyGuid (&gCurrentSelection->FormSetGuid, &gZeroGuid);
//
// Clear the menu history data.
//
while (!IsListEmpty (&mFBPrivate.FormBrowserEx2.FormViewHistoryHead)) {
MenuList = FORM_ENTRY_INFO_FROM_LINK (mFBPrivate.FormBrowserEx2.FormViewHistoryHead.ForwardLink);
RemoveEntryList (&MenuList->Link);
FreePool (MenuList);
}
}
gUserInput->Action = BROWSER_ACTION_NONE;
*ExitFlag = TRUE;
break;
case H2O_DISPLAY_ENGINE_EVT_TYPE_EXIT:
FBBroadcastEvent (Event);
gUserInput->Action = BROWSER_ACTION_NONE;
gCurrentSelection->Action = UI_ACTION_EXIT;
*ExitFlag = TRUE;
break;
case H2O_DISPLAY_ENGINE_EVT_TYPE_DEFAULT:
if (GetScuFormset () != NULL) {
Status = BroadcastOpenDByHotKeyEvt (H2O_DISPLAY_ENGINE_EVT_TYPE_DEFAULT);
if (EFI_ERROR (Status)) {
break;
}
}
if (FeaturePcdGet(PcdH2OSetupChangeDisplaySupported)) {
SetupDateChange.SetTime = FALSE;
REPORT_STATUS_CODE_EX (
EFI_PROGRESS_CODE,
EFI_SOFTWARE_DXE_RT_DRIVER | EFI_SW_RS_PC_SET_TIME,
0,
NULL,
&gH2OSetupChangeStatusCodeGuid,
(VOID *) &SetupDateChange,
sizeof (SETUP_DATE_CHANGE)
);
}
gUserInput->Action = BROWSER_ACTION_DEFAULT;
gUserInput->DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
*ExitFlag = TRUE;
break;
case H2O_DISPLAY_ENGINE_EVT_TYPE_SUBMIT_EXIT:
if (GetScuFormset () != NULL ||
CompareGuid (gCurrentSelection->FormSet->ClassGuid, &mSecureBootMgrFormSetGuid)) {
gUserInput->Action = BROWSER_ACTION_NONE;
Request = BROWSER_ACTION_NONE;
ShowSubmitDialog = TRUE;
Status = H2OSubmitSvcManager (&Request, &ShowSubmitDialog);
if (!EFI_ERROR (Status)) {
gUserInput->Action = Request;
if ((Request & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {
gCurrentSelection->Action = UI_ACTION_EXIT;
}
}
if (Status == EFI_NOT_FOUND || ShowSubmitDialog) {
//
// There is no H2OSubmitSvc protocol installed.
//
//
// Show original submit dialog if it is not hooked.
//
Status = BroadcastOpenDByHotKeyEvt (H2O_DISPLAY_ENGINE_EVT_TYPE_SUBMIT_EXIT);
if (EFI_ERROR (Status)) {
break;
}
gUserInput->Action |= BROWSER_ACTION_SUBMIT | BROWSER_ACTION_RESET;
gCurrentSelection->Action = UI_ACTION_EXIT;
}
} else {
gUserInput->Action = BROWSER_ACTION_SUBMIT;
}
*ExitFlag = TRUE;
break;
case H2O_DISPLAY_ENGINE_EVT_TYPE_DISCARD_EXIT:
if (!FormExitPolicy()) {
break;
}
gUserInput->Action = BROWSER_ACTION_FORM_EXIT;
*ExitFlag = TRUE;
break;
case H2O_DISPLAY_ENGINE_EVT_TYPE_SUBMIT:
case H2O_DISPLAY_ENGINE_EVT_TYPE_DISCARD:
case H2O_DISPLAY_ENGINE_EVT_TYPE_SHOW_HELP:
Status = BroadcastOpenDByHotKeyEvt (Event->Type);
break;
case H2O_DISPLAY_ENGINE_EVT_TYPE_TIMER:
Status = FBTimer (Private, Event);
if (gUserInput->Action != 0) {
*ExitFlag = TRUE;
}
break;
case H2O_DISPLAY_ENGINE_EVT_TYPE_HOT_KEY:
Status = FBHotKey (Event, ExitFlag);
break;
default:
DEBUG ((EFI_D_INFO, "Invalid H2O Display Engine Event: %d\n", Event->Type));
ASSERT (FALSE);
break;
}
return Status;
}
/**
OEM specifies whether Setup exits Page by ESC key.
This function customized the behavior that whether Setup exits Page so that
system able to boot when configuration is not changed.
@retval TRUE Exits FrontPage
@retval FALSE Don't exit FrontPage.
**/
BOOLEAN
EFIAPI
FormExitPolicy (
VOID
)
{
if (CompareGuid (&gCurrentSelection->FormSet->Guid, &gFrontPageFormSetGuid)) {
return FALSE;
}
return TRUE;
}
/**
Confirm how to handle the changed data.
@return Action BROWSER_ACTION_SUBMIT, BROWSER_ACTION_DISCARD or other values.
**/
UINTN
EFIAPI
ConfirmDataChange (
VOID
)
{
EFI_STATUS Status;
SETUP_DATE_CHANGE SetupDateChange;
if (GetScuFormset () != NULL ||
CompareGuid (gCurrentSelection->FormSet->ClassGuid, &mSecureBootMgrFormSetGuid)) {
Status = BroadcastOpenDByHotKeyEvt (H2O_DISPLAY_ENGINE_EVT_TYPE_DISCARD_EXIT);
if (!EFI_ERROR (Status)) {
gCurrentSelection->Action = UI_ACTION_EXIT;
if (FeaturePcdGet(PcdH2OSetupChangeDisplaySupported)) {
SetupDateChange.SetTime = FALSE;
REPORT_STATUS_CODE_EX (
EFI_PROGRESS_CODE,
EFI_SOFTWARE_DXE_RT_DRIVER | EFI_SW_RS_PC_SET_TIME,
0,
NULL,
&gH2OSetupChangeStatusCodeGuid,
(VOID *) &SetupDateChange,
sizeof (SETUP_DATE_CHANGE)
);
}
return BROWSER_ACTION_DISCARD;
} else {
return BROWSER_ACTION_NONE;
}
} else {
Status = BroadcastOpenDByHotKeyEvt (H2O_DISPLAY_ENGINE_EVT_TYPE_DISCARD_EXIT);
if (!EFI_ERROR (Status)) {
return BROWSER_ACTION_DISCARD;
} else {
return BROWSER_ACTION_NONE;
}
}
}
VOID
BrowserStatusProcess (
VOID
)
{
CHAR16 *ErrorInfo;
UINT8 TimeOut;
EFI_STRING_ID StringToken;
H2O_FORM_BROWSER_D Dialog;
EFI_IFR_OP_HEADER *OpCodeBuf;
if (gFormData->BrowserStatus == BROWSER_SUCCESS) {
return;
}
StringToken = 0;
OpCodeBuf = NULL;
if (gFormData->HighLightedStatement != NULL) {
OpCodeBuf = gFormData->HighLightedStatement->OpCode;
}
if (gFormData->BrowserStatus == (BROWSER_WARNING_IF)) {
ASSERT (OpCodeBuf != NULL && OpCodeBuf->OpCode == EFI_IFR_WARNING_IF_OP);
if (OpCodeBuf != NULL && OpCodeBuf->OpCode == EFI_IFR_WARNING_IF_OP) {
TimeOut = ((EFI_IFR_WARNING_IF *) OpCodeBuf)->TimeOut;
StringToken = ((EFI_IFR_WARNING_IF *) OpCodeBuf)->Warning;
}
} else {
TimeOut = 0;
if ((gFormData->BrowserStatus == (BROWSER_NO_SUBMIT_IF)) &&
(OpCodeBuf != NULL && OpCodeBuf->OpCode == EFI_IFR_NO_SUBMIT_IF_OP)) {
StringToken = ((EFI_IFR_NO_SUBMIT_IF *) OpCodeBuf)->Error;
} else if ((gFormData->BrowserStatus == (BROWSER_INCONSISTENT_IF)) &&
(OpCodeBuf != NULL && OpCodeBuf->OpCode == EFI_IFR_INCONSISTENT_IF_OP)) {
StringToken = ((EFI_IFR_INCONSISTENT_IF *) OpCodeBuf)->Error;
}
}
if (StringToken != 0) {
ErrorInfo = GetString (StringToken, gCurrentSelection->FormSet->HiiHandle);
} else if (gFormData->ErrorString != NULL) {
//
// Only used to compatible with old setup browser.
// Not use this field in new browser core.
//
ErrorInfo = gFormData->ErrorString;
} else {
switch (gFormData->BrowserStatus) {
case BROWSER_SUBMIT_FAIL:
ErrorInfo = gSaveFailed;
break;
case BROWSER_FORM_NOT_FOUND:
ErrorInfo = gFormNotFound;
break;
case BROWSER_FORM_SUPPRESS:
ErrorInfo = gFormSuppress;
break;
case BROWSER_PROTOCOL_NOT_FOUND:
ErrorInfo = gProtocolNotFound;
break;
default:
ErrorInfo = gBrowserError;
break;
}
}
if (ErrorInfo != NULL) {
CreateSimpleDialog (H2O_FORM_BROWSER_D_TYPE_SELECTION, 0, NULL, 1, &ErrorInfo, 1, &Dialog);
}
if (StringToken != 0) {
FreePool (ErrorInfo);
}
}
/**
Check if question's VarOffset value exceed the varstore size for all questions in the form.
@param[in] Form Pointer to the current form
**/
STATIC
VOID
CheckQuestionVarOffset (
IN FORM_BROWSER_FORM *Form
)
{
LIST_ENTRY *Link;
FORM_BROWSER_STATEMENT *Statement;
H2O_FORM_BROWSER_D Dialog;
CHAR16 *StrArray[2];
CHAR16 *ValueMsg;
if (Form == NULL) {
return;
}
Link = GetFirstNode (&Form->StatementListHead);
while (!IsNull (&Form->StatementListHead, Link)) {
Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
Link = GetNextNode (&Form->StatementListHead, Link);
if (Statement->Storage != NULL &&
(Statement->Storage->Type == EFI_HII_VARSTORE_BUFFER ||
Statement->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) &&
Statement->VarStoreInfo.VarOffset >= Statement->Storage->Size) {
ValueMsg = CatSPrint (
NULL,
L"(%s: question variable offset=0x%x, varstore size=0x%x)",
Statement->Statement.Prompt,
Statement->VarStoreInfo.VarOffset,
Statement->Storage->Size
);
if (ValueMsg != NULL) {
StrArray[0] = L"Question variable offset exceeds the varstore size!";
StrArray[1] = ValueMsg;
DestroyEventQueue (&mFBPrivate);
ZeroMem (&Dialog, sizeof (H2O_FORM_BROWSER_D));
CreateSimpleDialog (H2O_FORM_BROWSER_D_TYPE_MSG, 0, NULL, 2, StrArray, 1, &Dialog);
FreePool (ValueMsg);
}
}
}
}
/**
Check if the question value is valid or not
@param[in] Question The pointer to check question
@retval EFI_SUCCESS Question value is valid
@retval EFI_NOT_FOUND Question value is mismatch
**/
EFI_STATUS
CheckQuestionValue (
IN FORM_BROWSER_STATEMENT *Question
)
{
EFI_STATUS Status;
EFI_HII_VALUE HiiValue;
UINTN Index;
UINTN Index2;
UINT8 *ValueArray;
UINT8 ValueType;
EFI_IFR_ORDERED_LIST *OrderList;
BOOLEAN ValueInvalid;
QUESTION_OPTION *OneOfOption;
EFI_HII_VALUE *QuestionHiiValue;
H2O_FORM_BROWSER_O *Option;
H2O_FORM_BROWSER_S *Statement;
CHAR16 *ErrorMsg;
CHAR16 *MismatchInfo;
CHAR16 *StrArray[2];
H2O_FORM_BROWSER_D Dialog;
Status = EFI_SUCCESS;
QuestionHiiValue = &Question->HiiValue;
Statement = &Question->Statement;
switch (Question->OpCode->OpCode) {
case EFI_IFR_ONE_OF_OP:
if (Statement->NumberOfOptions == 0) {
break;
}
OneOfOption = ValueToOption (Question, QuestionHiiValue);
if (OneOfOption != NULL) {
break;
}
ErrorMsg = GetString (STRING_TOKEN (OPTION_MISMATCH), mHiiHandle);
MismatchInfo = CatSPrint (NULL, L"(%s: mismatch value is %d.)", Statement->Prompt, QuestionHiiValue->Value.u64);
if (ErrorMsg != NULL && MismatchInfo != NULL) {
DestroyEventQueue (&mFBPrivate);
StrArray[0] = ErrorMsg;
StrArray[1] = MismatchInfo;
ZeroMem (&Dialog, sizeof (H2O_FORM_BROWSER_D));
CreateSimpleDialog (H2O_FORM_BROWSER_D_TYPE_MSG, 0, NULL, 2, StrArray, 1, &Dialog);
FreePool ((VOID *) ErrorMsg);
FreePool ((VOID *) MismatchInfo);
}
//
// Force the Question value to be valid
// Exit current DisplayForm with new value.
//
Option = &Statement->Options[0];
mDisplayStatement.OpCode = Question->OpCode;
gUserInput->SelectedStatement = &mDisplayStatement;
gUserInput->InputValue.Type = Option->HiiValue.Type;
switch (gUserInput->InputValue.Type) {
case EFI_IFR_TYPE_NUM_SIZE_8:
gUserInput->InputValue.Value.u8 = Option->HiiValue.Value.u8;
break;
case EFI_IFR_TYPE_NUM_SIZE_16:
CopyMem (&gUserInput->InputValue.Value.u16, &Option->HiiValue.Value.u16, sizeof (UINT16));
break;
case EFI_IFR_TYPE_NUM_SIZE_32:
CopyMem (&gUserInput->InputValue.Value.u32, &Option->HiiValue.Value.u32, sizeof (UINT32));
break;
case EFI_IFR_TYPE_NUM_SIZE_64:
CopyMem (&gUserInput->InputValue.Value.u64, &Option->HiiValue.Value.u64, sizeof (UINT64));
break;
default:
ASSERT (FALSE);
break;
}
return EFI_NOT_FOUND;
case EFI_IFR_ORDERED_LIST_OP:
if (Statement->NumberOfOptions == 0) {
break;
}
OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;
Option = &Statement->Options[0];
ValueType = Option->HiiValue.Type;
ValueArray = QuestionHiiValue->Buffer;
HiiValue.Type = ValueType;
HiiValue.Value.u64 = 0;
for (Index = 0; Index < OrderList->MaxContainers; Index++) {
HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
if (HiiValue.Value.u64 == 0) {
//
// Values for the options in ordered lists should never be a 0
//
break;
}
OneOfOption = ValueToOption (Question, &HiiValue);
if (OneOfOption != NULL) {
continue;
}
ErrorMsg = GetString (STRING_TOKEN (OPTION_MISMATCH), mHiiHandle);
MismatchInfo = CatSPrint (NULL, L"(%s: mismatch value is %d.)", Statement->Prompt, HiiValue.Value.u64);
if (ErrorMsg != NULL && MismatchInfo != NULL) {
DestroyEventQueue (&mFBPrivate);
StrArray[0] = ErrorMsg;
StrArray[1] = MismatchInfo;
ZeroMem (&Dialog, sizeof (H2O_FORM_BROWSER_D));
CreateSimpleDialog (H2O_FORM_BROWSER_D_TYPE_MSG, 0, NULL, 2, StrArray, 1, &Dialog);
FreePool ((VOID *) ErrorMsg);
FreePool ((VOID *) MismatchInfo);
}
//
// The initial value of the orderedlist is invalid, force to be valid value
// Exit current DisplayForm with new value.
//
mDisplayStatement.OpCode = Question->OpCode;
gUserInput->SelectedStatement = &mDisplayStatement;
ValueArray = AllocateZeroPool (QuestionHiiValue->BufferLen);
ASSERT (ValueArray != NULL);
if (ValueArray == NULL) {
break;
}
gUserInput->InputValue.Buffer = ValueArray;
gUserInput->InputValue.BufferLen = QuestionHiiValue->BufferLen;
gUserInput->InputValue.Type = QuestionHiiValue->Type;
for (Index2 = 0; Index2 < Statement->NumberOfOptions && Index2 < OrderList->MaxContainers; Index2++) {
Option = &Statement->Options[Index2];
SetArrayData (ValueArray, ValueType, Index2, Option->HiiValue.Value.u64);
}
if (Index2 < OrderList->MaxContainers) {
SetArrayData (ValueArray, ValueType, Index2, 0);
}
return EFI_NOT_FOUND;
}
//
// If valid option more than the max container, skip these options.
//
if (Index >= OrderList->MaxContainers) {
break;
}
//
// Search the other options, try to find the one not in the container.
//
ValueArray = QuestionHiiValue->Buffer;
ValueInvalid = FALSE;
for (Index2 = 0; Index2 < Statement->NumberOfOptions; Index2++) {
Option = &Statement->Options[Index2];
if (FindArrayData (ValueArray, ValueType, Option->HiiValue.Value.u64, NULL)) {
continue;
}
if (!ValueInvalid) {
ValueInvalid = TRUE;
ErrorMsg = GetString (STRING_TOKEN (OPTION_MISMATCH), mHiiHandle);
if (ErrorMsg != NULL) {
DestroyEventQueue (&mFBPrivate);
ZeroMem (&Dialog, sizeof (H2O_FORM_BROWSER_D));
CreateSimpleDialog (H2O_FORM_BROWSER_D_TYPE_MSG, 0, NULL, 1, &ErrorMsg, 1, &Dialog);
FreePool ((VOID *) ErrorMsg);
}
//
// The initial value of the orderedlist is invalid, force to be valid value
// Exit current DisplayForm with new value.
//
mDisplayStatement.OpCode = Question->OpCode;
gUserInput->SelectedStatement = &mDisplayStatement;
ValueArray = AllocateCopyPool (QuestionHiiValue->BufferLen, QuestionHiiValue->Buffer);
ASSERT (ValueArray != NULL);
if (ValueArray == NULL) {
break;
}
gUserInput->InputValue.Buffer = ValueArray;
gUserInput->InputValue.BufferLen = QuestionHiiValue->BufferLen;
gUserInput->InputValue.Type = QuestionHiiValue->Type;
}
SetArrayData (ValueArray, ValueType, Index++, Option->HiiValue.Value.u64);
}
if (ValueInvalid) {
return EFI_NOT_FOUND;
}
break;
default:
break;
}
return Status;
}
/**
Check if there is a question value is mismatch
@param[in] Form The pointer of form which contains Questions
@retval TRUE There is a question value is mismatch
@retval FALSE There is not a question value is mismatch
**/
BOOLEAN
IsQuestionValueMismatch (
IN FORM_BROWSER_FORM *Form
)
{
FORM_BROWSER_STATEMENT *Statement;
LIST_ENTRY *Link;
if (Form == NULL) {
return FALSE;
}
Link = GetFirstNode (&Form->StatementListHead);
while (!IsNull (&Form->StatementListHead, Link)) {
Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
Link = GetNextNode (&Form->StatementListHead, Link);
if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) >= ExpressSuppress) {
continue;
}
if (CheckQuestionValue (Statement) == EFI_NOT_FOUND) {
return TRUE;
}
}
return FALSE;
}
EFI_STATUS
EFIAPI
FormDisplay (
IN FORM_DISPLAY_ENGINE_FORM *FormData,
OUT USER_INPUT *UserInputData
)
{
H2O_DISPLAY_ENGINE_EVT *Event;
BOOLEAN ExitFlag;
H2O_DISPLAY_ENGINE_EVT_OPEN_P OpenP;
BOOLEAN InIdleState;
ASSERT (FormData != NULL);
if (FormData == NULL) {
return EFI_INVALID_PARAMETER;
}
gUserInput = UserInputData;
gFormData = FormData;
//
// Process the status info first.
//
BrowserStatusProcess();
if (UserInputData == NULL) {
//
// UserInputData == NULL, means only need to print the error info, return here.
//
return EFI_SUCCESS;
}
FBUpdateSMInfo (&mFBPrivate);
if (mFBPrivate.Repaint) {
FBRepaint (&mFBPrivate);
mFBPrivate.Repaint = FALSE;
} else {
ZeroMem (&OpenP, sizeof (H2O_DISPLAY_ENGINE_EVT_OPEN_P));
OpenP.Hdr.Size = sizeof (H2O_DISPLAY_ENGINE_EVT_OPEN_P);
OpenP.Hdr.Target = H2O_DISPLAY_ENGINE_EVT_TARGET_FORM_BROWSER;
OpenP.Hdr.Type = H2O_DISPLAY_ENGINE_EVT_TYPE_OPEN_P;
FBBroadcastEvent ((H2O_DISPLAY_ENGINE_EVT*)&OpenP);
}
//
// If question value is mismatch and correctable, pop up warning dialog, correct it and return EFI_NOT_FOUND to refresh form.
// If question VarOffset value exceeds the varstore size, only pop up warning dialog because it can't be corrected by browser.
//
if (IsQuestionValueMismatch (gCurrentSelection->Form)) {
return EFI_NOT_FOUND;
}
CheckQuestionVarOffset (gCurrentSelection->Form);
//
// event loop
//
InIdleState = FALSE;
while (1) {
Event = NULL;
GetNextEvent (&Event);
if (Event == NULL && !mRefreshFormSet && !mRefreshForm) {
if (!InIdleState) {
InIdleState = TRUE;
if (FeaturePcdGet (PcdH2OBdsCpFormBrowserIdleBeforeSupported)) {
TriggerCpFormBrowserIdleBefore ();
}
}
continue;
} else {
if (InIdleState) {
InIdleState = FALSE;
if (FeaturePcdGet (PcdH2OBdsCpFormBrowserIdleAfterSupported)) {
TriggerCpFormBrowserIdleAfter ();
}
}
}
if (Event == NULL) {
if (mRefreshFormSet || mRefreshForm) {
gUserInput->Action = BROWSER_ACTION_NONE;
gCurrentSelection->Action = (mRefreshFormSet) ? UI_ACTION_REFRESH_FORMSET : UI_ACTION_REFRESH_FORM;
if (mFBPrivate.FB.CurrentQ != NULL && mFBPrivate.FB.CurrentQ->QuestionId == 0) {
mCurFakeQestId = ((FORM_BROWSER_STATEMENT *)(FORM_BROWSER_STATEMENT_FROM_H2O_STATEMENT(mFBPrivate.FB.CurrentQ)))->FakeQuestionId;
}
break;
}
continue;
}
FBEventCallback (Event, &ExitFlag);
if (ExitFlag) {
FreePool (Event);
break;
}
FreePool (Event);
}
mRefreshFormSet = FALSE;
mRefreshForm = FALSE;
DestroyEventQueue (&mFBPrivate);
return EFI_SUCCESS;
}