+/**\r
+ Build the FRAMEWORK_EFI_IFR_DATA_ARRAY which will be used to pass to \r
+ EFI_FORM_CALLBACK_PROTOCOL.Callback. Check definition of FRAMEWORK_EFI_IFR_DATA_ARRAY\r
+ for details.\r
+\r
+ ASSERT if the Question Type is not EFI_IFR_TYPE_NUM_SIZE_* or EFI_IFR_TYPE_STRING.\r
+ \r
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL\r
+ @param QuestionId The Question ID.\r
+ @param Type The Question Type.\r
+ @param Value The Question Value.\r
+ @param NvMapAllocated On output indicates if a buffer is allocated for NvMap.\r
+ \r
+ @return A pointer to FRAMEWORK_EFI_IFR_DATA_ARRAY. The caller must free this buffer allocated.\r
+**/ \r
+FRAMEWORK_EFI_IFR_DATA_ARRAY *\r
+CreateIfrDataArray (\r
+ IN CONFIG_ACCESS_PRIVATE *ConfigAccess,\r
+ IN EFI_QUESTION_ID QuestionId,\r
+ IN UINT8 Type,\r
+ IN EFI_IFR_TYPE_VALUE *Value,\r
+ OUT BOOLEAN *NvMapAllocated\r
+ )\r
+{\r
+ FRAMEWORK_EFI_IFR_DATA_ARRAY *IfrDataArray;\r
+ FRAMEWORK_EFI_IFR_DATA_ENTRY *IfrDataEntry;\r
+ UINTN BrowserDataSize;\r
+ FORMSET_STORAGE *BufferStorage;\r
+ EFI_STATUS Status;\r
+ UINTN Size;\r
+ UINTN StringSize;\r
+ EFI_STRING String;\r
+\r
+ *NvMapAllocated = FALSE;\r
+\r
+ String = NULL;\r
+\r
+ switch (Type) {\r
+ case EFI_IFR_TYPE_NUM_SIZE_8:\r
+ case EFI_IFR_TYPE_NUM_SIZE_16:\r
+ case EFI_IFR_TYPE_NUM_SIZE_32:\r
+ case EFI_IFR_TYPE_NUM_SIZE_64:\r
+ case EFI_IFR_TYPE_BOOLEAN:\r
+ Size = sizeof (*Value);\r
+ break;\r
+\r
+ case EFI_IFR_TYPE_STRING:\r
+ StringSize = 0;\r
+ Status = HiiLibGetString (ConfigAccess->ThunkContext->UefiHiiHandle, Value->string, String, &StringSize);\r
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
+\r
+ String = AllocateZeroPool (StringSize);\r
+ ASSERT (String != NULL);\r
+\r
+ Status = HiiLibGetString (ConfigAccess->ThunkContext->UefiHiiHandle, Value->string, String, &StringSize);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Size = StringSize;\r
+ break;\r
+ \r
+ default:\r
+ ASSERT (FALSE);\r
+ Size = 0;\r
+ break;\r
+ }\r
+\r
+ IfrDataArray = AllocateZeroPool (sizeof (FRAMEWORK_EFI_IFR_DATA_ARRAY) + sizeof (FRAMEWORK_EFI_IFR_DATA_ENTRY) + Size);\r
+ ASSERT (IfrDataArray != NULL);\r
+\r
+ BufferStorage = GetStorageFromQuestionId (ConfigAccess->ThunkContext->FormSet, QuestionId);\r
+\r
+ if (BufferStorage == NULL) {\r
+ //\r
+ // The QuestionId is not associated with a Buffer Storage.\r
+ // Try to get the first Buffer Storage then.\r
+ //\r
+ BufferStorage = GetFirstStorageOfFormSet (ConfigAccess->ThunkContext->FormSet);\r
+ }\r
+ \r
+ if (BufferStorage != NULL) {\r
+ BrowserDataSize = BufferStorage->Size;\r
+\r
+ if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r
+ *NvMapAllocated = TRUE;\r
+ IfrDataArray->NvRamMap = AllocateZeroPool (BrowserDataSize);\r
+ } else {\r
+ *NvMapAllocated = FALSE;\r
+ IfrDataArray->NvRamMap = ConfigAccess->ThunkContext->NvMapOverride;\r
+ }\r
+ \r
+ Status = GetBrowserData (&BufferStorage->Guid, BufferStorage->Name, &BrowserDataSize, IfrDataArray->NvRamMap);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ IfrDataEntry = (FRAMEWORK_EFI_IFR_DATA_ENTRY *) (IfrDataArray + 1);\r
+\r
+ switch (Type) {\r
+ case EFI_IFR_TYPE_NUM_SIZE_8:\r
+ case EFI_IFR_TYPE_NUM_SIZE_16:\r
+ case EFI_IFR_TYPE_NUM_SIZE_32:\r
+ case EFI_IFR_TYPE_NUM_SIZE_64:\r
+ case EFI_IFR_TYPE_BOOLEAN:\r
+ CopyMem (&IfrDataEntry->Data, &(Value->u8), sizeof (*Value));\r
+ break;\r
+\r
+ case EFI_IFR_TYPE_STRING:\r
+ ASSERT (String != NULL);\r
+ StrCpy ((CHAR16 *) &IfrDataEntry->Data, String);\r
+ FreePool (String);\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Need to fiil in the information for the rest of field for FRAMEWORK_EFI_IFR_DATA_ENTRY.\r
+ // It seems that no implementation is found to use other fields. Leave them uninitialized for now.\r
+ //\r
+ //UINT8 OpCode; // Likely a string, numeric, or one-of\r
+ //UINT8 Length; // Length of the FRAMEWORK_EFI_IFR_DATA_ENTRY packet\r
+ //UINT16 Flags; // Flags settings to determine what behavior is desired from the browser after the callback\r
+ //VOID *Data; // The data in the form based on the op-code type - this is not a pointer to the data, the data follows immediately\r
+ // If the OpCode is a OneOf or Numeric type - Data is a UINT16 value\r
+ // If the OpCode is a String type - Data is a CHAR16[x] type\r
+ // If the OpCode is a Checkbox type - Data is a UINT8 value\r
+ // If the OpCode is a NV Access type - Data is a FRAMEWORK_EFI_IFR_NV_DATA structure\r
+ }\r
+\r
+ return IfrDataArray;\r
+}\r
+\r
+/**\r
+ If a NvMapOverride is passed in to EFI_FORM_BROWSER_PROTOCOL.SendForm, the Form Browser\r
+ needs to be informed when data changed in NvMapOverride. This function will invoke\r
+ SetBrowserData () to set internal data of Form Browser.\r
+\r
+ @param ConfigAccess The Config Access Private Context.\r
+ @param QuestionId The Question Id that invokes the callback.\r
+ \r
+\r
+**/\r
+VOID\r
+SyncBrowserDataForNvMapOverride (\r
+ IN CONST CONFIG_ACCESS_PRIVATE *ConfigAccess,\r
+ IN EFI_QUESTION_ID QuestionId\r
+ )\r
+{\r
+ FORMSET_STORAGE *BufferStorage;\r
+ EFI_STATUS Status;\r
+ UINTN BrowserDataSize;\r
+\r
+ if (ConfigAccess->ThunkContext->NvMapOverride != NULL) {\r
+\r
+ BufferStorage = GetStorageFromQuestionId (ConfigAccess->ThunkContext->FormSet, QuestionId);\r
+\r
+ if (BufferStorage == NULL) {\r
+ //\r
+ // QuestionId is a statement without Storage.\r
+ // 1) It is a Goto. \r
+ // \r
+ //\r
+ BufferStorage = GetFirstStorageOfFormSet (ConfigAccess->ThunkContext->FormSet);\r
+ }\r
+\r
+ //\r
+ // If NvMapOverride is not NULL, this Form must have at least one Buffer Type Variable Storage.\r
+ //\r
+ ASSERT (BufferStorage != NULL);\r
+ \r
+ BrowserDataSize = BufferStorage->Size;\r
+\r
+ Status = SetBrowserData (&BufferStorage->Guid, BufferStorage->Name, BrowserDataSize, ConfigAccess->ThunkContext->NvMapOverride, NULL);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+}\r
+\r
+/**\r
+ Free up resource allocated for a FRAMEWORK_EFI_IFR_DATA_ARRAY by CreateIfrDataArray ().\r
+\r
+ @param Array The FRAMEWORK_EFI_IFR_DATA_ARRAY allocated.\r
+ @param NvMapAllocated If the NvRamMap is allocated for FRAMEWORK_EFI_IFR_DATA_ARRAY.\r
+\r
+**/\r
+VOID\r
+DestroyIfrDataArray (\r
+ IN FRAMEWORK_EFI_IFR_DATA_ARRAY *Array,\r
+ IN BOOLEAN NvMapAllocated\r
+ )\r
+{\r
+ if (Array != NULL) {\r
+ if (NvMapAllocated) {\r
+ FreePool (Array->NvRamMap);\r
+ }\r
+\r
+ FreePool (Array);\r
+ }\r
+}\r
+\r
+/**\r
+ Get the ONE_OF_OPTION_MAP_ENTRY for a QuestionId that invokes the \r
+ EFI_FORM_CALLBACK_PROTOCOL.Callback. The information is needed as\r
+ the callback mechanism for EFI_IFR_ONE_OF_OPTION is changed from \r
+ EFI_IFR_ONE_OF_OPTION in Framework IFR. Check EFI_IFR_GUID_OPTIONKEY\r
+ for detailed information.\r
+\r
+ @param ThunkContext The Thunk Context.\r
+ @param QuestionId The Question Id.\r
+ @param Type The Question Type.\r
+ @param Value The One Of Option's value.\r
+\r
+ @return The ONE_OF_OPTION_MAP_ENTRY found.\r
+ @retval NULL If no entry is found.\r
+**/\r
+ONE_OF_OPTION_MAP_ENTRY *\r
+GetOneOfOptionMapEntry (\r
+ IN HII_THUNK_CONTEXT *ThunkContext,\r
+ IN EFI_QUESTION_ID QuestionId,\r
+ IN UINT8 Type,\r
+ IN EFI_IFR_TYPE_VALUE *Value\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *Link2;\r
+ ONE_OF_OPTION_MAP_ENTRY *OneOfOptionMapEntry;\r
+ ONE_OF_OPTION_MAP *OneOfOptionMap;\r
+ FORM_BROWSER_FORMSET *FormSet;\r
+\r
+ FormSet = ThunkContext->FormSet;\r
+\r
+ Link = GetFirstNode (&FormSet->OneOfOptionMapListHead);\r
+\r
+ while (!IsNull (&FormSet->OneOfOptionMapListHead, Link)) {\r
+ OneOfOptionMap = ONE_OF_OPTION_MAP_FROM_LINK(Link);\r
+ if (OneOfOptionMap->QuestionId == QuestionId) {\r
+ ASSERT (OneOfOptionMap->ValueType == Type);\r
+\r
+ Link2 = GetFirstNode (&OneOfOptionMap->OneOfOptionMapEntryListHead);\r
+\r
+ while (!IsNull (&OneOfOptionMap->OneOfOptionMapEntryListHead, Link2)) {\r
+ OneOfOptionMapEntry = ONE_OF_OPTION_MAP_ENTRY_FROM_LINK (Link2);\r
+\r
+ if (CompareMem (Value, &OneOfOptionMapEntry->Value, sizeof (EFI_IFR_TYPE_VALUE)) == 0) {\r
+ return OneOfOptionMapEntry;\r
+ }\r
+\r
+ Link2 = GetNextNode (&OneOfOptionMap->OneOfOptionMapEntryListHead, Link2);\r
+ }\r
+ }\r
+\r
+ Link = GetNextNode (&FormSet->OneOfOptionMapListHead, Link);\r
+ }\r
+\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Functions which are registered to receive notification of\r
+ database events have this prototype. The actual event is encoded\r
+ in NotifyType. The following table describes how PackageType,\r
+ PackageGuid, Handle, and Package are used for each of the\r
+ notification types.\r
+\r
+ If any Pakcage List in database is updated, mHiiPackageListUpdated\r
+ will be set. If mHiiPackageListUpdated is set, Framework ThunkCallback()\r
+ will force the UEFI Setup Browser to save the uncommitted data. This\r
+ is needed as Framework's Callback function may dynamically update\r
+ opcode in a Package List. UEFI Setup Browser will quit itself and reparse\r
+ the Package List's IFR and display it. UEFI Config Access's implementation\r
+ is required to save the modified (SetBrowserData or directly save the data\r
+ to NV storage). But Framework HII Modules is not aware of this rule. Therefore,\r
+ we will enforce the rule in ThunkCallback (). The side effect of force saving\r
+ of NV data is the NV flag in browser may not flag a update as data has already\r
+ been saved to NV storage.\r
+\r
+ @param PackageType Package type of the notification.\r
+\r
+ @param PackageGuid If PackageType is\r
+ EFI_HII_PACKAGE_TYPE_GUID, then this is\r
+ the pointer to the GUID from the Guid\r
+ field of EFI_HII_PACKAGE_GUID_HEADER.\r
+ Otherwise, it must be NULL.\r
+\r
+ @param Package Points to the package referred to by the\r
+ notification Handle The handle of the package\r
+ list which contains the specified package.\r
+\r
+ @param Handle The HII handle.\r
+\r
+ @param NotifyType The type of change concerning the\r
+ database. See\r
+ EFI_HII_DATABASE_NOTIFY_TYPE.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FormUpdateNotify (\r
+ IN UINT8 PackageType,\r
+ IN CONST EFI_GUID *PackageGuid,\r
+ IN CONST EFI_HII_PACKAGE_HEADER *Package,\r
+ IN EFI_HII_HANDLE Handle,\r
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType\r
+ )\r
+{\r
+ mHiiPackageListUpdated = TRUE;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r