]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Universal/SetupBrowserDxe/Setup.c
Refine the logic when return success, should not clean the buffer in this case.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Setup.c
... / ...
CommitLineData
1/** @file\r
2Entry and initialization module for the browser.\r
3\r
4Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "Setup.h"\r
16\r
17SETUP_DRIVER_PRIVATE_DATA mPrivateData = {\r
18 SETUP_DRIVER_SIGNATURE,\r
19 NULL,\r
20 {\r
21 SendForm,\r
22 BrowserCallback\r
23 },\r
24 {\r
25 SetScope,\r
26 RegisterHotKey,\r
27 RegiserExitHandler,\r
28 SaveReminder\r
29 },\r
30 {\r
31 BROWSER_EXTENSION2_VERSION_1,\r
32 SetScope,\r
33 RegisterHotKey,\r
34 RegiserExitHandler,\r
35 IsBrowserDataModified,\r
36 ExecuteAction,\r
37 }\r
38};\r
39\r
40EFI_HII_DATABASE_PROTOCOL *mHiiDatabase;\r
41EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting;\r
42EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText;\r
43EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay;\r
44\r
45UINTN gBrowserContextCount = 0;\r
46LIST_ENTRY gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList);\r
47LIST_ENTRY gBrowserFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserFormSetList);\r
48LIST_ENTRY gBrowserHotKeyList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserHotKeyList);\r
49LIST_ENTRY gBrowserStorageList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserStorageList);\r
50\r
51BOOLEAN gFinishRetrieveCall;\r
52BOOLEAN gResetRequired;\r
53BOOLEAN gExitRequired;\r
54BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel;\r
55BOOLEAN mBrowserScopeFirstSet = TRUE;\r
56EXIT_HANDLER ExitHandlerFunction = NULL;\r
57FORM_BROWSER_FORMSET *mSystemLevelFormSet;\r
58\r
59//\r
60// Browser Global Strings\r
61//\r
62CHAR16 *gEmptyString;\r
63CHAR16 *mUnknownString = L"!";\r
64\r
65EFI_GUID gZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};\r
66\r
67extern UINT32 gBrowserStatus;\r
68extern CHAR16 *gErrorInfo;\r
69extern EFI_GUID mCurrentFormSetGuid;\r
70extern EFI_HII_HANDLE mCurrentHiiHandle;\r
71extern UINT16 mCurrentFormId;\r
72extern FORM_DISPLAY_ENGINE_FORM gDisplayFormData;\r
73\r
74/**\r
75 Create a menu with specified formset GUID and form ID, and add it as a child\r
76 of the given parent menu.\r
77\r
78 @param HiiHandle Hii handle related to this formset.\r
79 @param FormSetGuid The Formset Guid of menu to be added.\r
80 @param FormId The Form ID of menu to be added.\r
81 @param QuestionId The question id of this menu to be added.\r
82\r
83 @return A pointer to the newly added menu or NULL if memory is insufficient.\r
84\r
85**/\r
86FORM_ENTRY_INFO *\r
87UiAddMenuList (\r
88 IN EFI_HII_HANDLE HiiHandle,\r
89 IN EFI_GUID *FormSetGuid,\r
90 IN UINT16 FormId,\r
91 IN UINT16 QuestionId\r
92 )\r
93{\r
94 FORM_ENTRY_INFO *MenuList;\r
95\r
96 MenuList = AllocateZeroPool (sizeof (FORM_ENTRY_INFO));\r
97 if (MenuList == NULL) {\r
98 return NULL;\r
99 }\r
100\r
101 MenuList->Signature = FORM_ENTRY_INFO_SIGNATURE;\r
102\r
103 MenuList->HiiHandle = HiiHandle;\r
104 CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));\r
105 MenuList->FormId = FormId;\r
106 MenuList->QuestionId = QuestionId;\r
107\r
108 //\r
109 // If parent is not specified, it is the root Form of a Formset\r
110 //\r
111 InsertTailList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);\r
112\r
113 return MenuList;\r
114}\r
115\r
116/**\r
117 Return the form id for the input hiihandle and formset.\r
118\r
119 @param HiiHandle HiiHandle for FormSet.\r
120 @param FormSetGuid The Formset GUID of the menu to search.\r
121\r
122 @return First form's id for this form set.\r
123\r
124**/\r
125EFI_FORM_ID\r
126GetFirstFormId (\r
127 IN EFI_HII_HANDLE HiiHandle,\r
128 IN EFI_GUID *FormSetGuid\r
129 )\r
130{\r
131 LIST_ENTRY *Link;\r
132 FORM_BROWSER_FORM *Form;\r
133\r
134 Link = GetFirstNode (&gCurrentSelection->FormSet->FormListHead);\r
135 Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
136\r
137 return Form->FormId;\r
138}\r
139\r
140/**\r
141 Search Menu with given FormSetGuid and FormId in all cached menu list.\r
142\r
143 @param HiiHandle HiiHandle for FormSet.\r
144 @param FormSetGuid The Formset GUID of the menu to search.\r
145 @param FormId The Form ID of menu to search.\r
146\r
147 @return A pointer to menu found or NULL if not found.\r
148\r
149**/\r
150FORM_ENTRY_INFO *\r
151UiFindMenuList (\r
152 IN EFI_HII_HANDLE HiiHandle, \r
153 IN EFI_GUID *FormSetGuid,\r
154 IN UINT16 FormId\r
155 )\r
156{\r
157 LIST_ENTRY *Link;\r
158 FORM_ENTRY_INFO *MenuList;\r
159 FORM_ENTRY_INFO *RetMenu;\r
160 EFI_FORM_ID FirstFormId;\r
161\r
162 RetMenu = NULL;\r
163\r
164 Link = GetFirstNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);\r
165 while (!IsNull (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link)) {\r
166 MenuList = FORM_ENTRY_INFO_FROM_LINK (Link);\r
167 Link = GetNextNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link);\r
168 \r
169 //\r
170 // If already find the menu, free the menus behind it.\r
171 //\r
172 if (RetMenu != NULL) {\r
173 RemoveEntryList (&MenuList->Link);\r
174 FreePool (MenuList);\r
175 continue;\r
176 }\r
177\r
178 //\r
179 // Find the same FromSet.\r
180 //\r
181 if (MenuList->HiiHandle == HiiHandle) {\r
182 if (CompareGuid (&MenuList->FormSetGuid, &gZeroGuid)) {\r
183 //\r
184 // FormSetGuid is not specified.\r
185 //\r
186 RetMenu = MenuList;\r
187 } else if (CompareGuid (&MenuList->FormSetGuid, FormSetGuid)) {\r
188 if (MenuList->FormId == FormId) {\r
189 RetMenu = MenuList;\r
190 } else if (FormId == 0 || MenuList->FormId == 0 ) {\r
191 FirstFormId = GetFirstFormId (HiiHandle, FormSetGuid);\r
192 if ((FormId == 0 && FirstFormId == MenuList->FormId) || (MenuList->FormId ==0 && FirstFormId == FormId)) {\r
193 RetMenu = MenuList;\r
194 }\r
195 }\r
196 }\r
197 }\r
198 }\r
199\r
200 return RetMenu;\r
201}\r
202\r
203/**\r
204 Find parent menu for current menu.\r
205\r
206 @param CurrentMenu Current Menu\r
207\r
208 @retval The parent menu for current menu.\r
209**/\r
210FORM_ENTRY_INFO *\r
211UiFindParentMenu (\r
212 IN FORM_ENTRY_INFO *CurrentMenu\r
213 )\r
214{\r
215 FORM_ENTRY_INFO *ParentMenu;\r
216\r
217 ParentMenu = NULL;\r
218 if (CurrentMenu->Link.BackLink != &mPrivateData.FormBrowserEx2.FormViewHistoryHead) {\r
219 ParentMenu = FORM_ENTRY_INFO_FROM_LINK (CurrentMenu->Link.BackLink);\r
220 }\r
221\r
222 return ParentMenu;\r
223}\r
224\r
225/**\r
226 Free Menu list linked list.\r
227\r
228 @param MenuListHead One Menu list point in the menu list.\r
229\r
230**/\r
231VOID\r
232UiFreeMenuList (\r
233 LIST_ENTRY *MenuListHead\r
234 )\r
235{\r
236 FORM_ENTRY_INFO *MenuList;\r
237\r
238 while (!IsListEmpty (MenuListHead)) {\r
239 MenuList = FORM_ENTRY_INFO_FROM_LINK (MenuListHead->ForwardLink);\r
240 RemoveEntryList (&MenuList->Link);\r
241\r
242 FreePool (MenuList);\r
243 }\r
244}\r
245\r
246/**\r
247 Load all hii formset to the browser.\r
248\r
249**/\r
250VOID\r
251LoadAllHiiFormset (\r
252 VOID\r
253 )\r
254{\r
255 FORM_BROWSER_FORMSET *LocalFormSet;\r
256 EFI_HII_HANDLE *HiiHandles;\r
257 UINTN Index;\r
258 EFI_GUID ZeroGuid;\r
259 EFI_STATUS Status;\r
260 FORM_BROWSER_FORMSET *OldFormset;\r
261 BOOLEAN OldRetrieveValue;\r
262\r
263 OldFormset = mSystemLevelFormSet;\r
264 OldRetrieveValue = gFinishRetrieveCall;\r
265 gFinishRetrieveCall = FALSE;\r
266\r
267 //\r
268 // Get all the Hii handles\r
269 //\r
270 HiiHandles = HiiGetHiiHandles (NULL);\r
271 ASSERT (HiiHandles != NULL);\r
272\r
273 //\r
274 // Search for formset of each class type\r
275 //\r
276 for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
277 //\r
278 // Check HiiHandles[Index] does exist in global maintain list.\r
279 //\r
280 if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) {\r
281 continue;\r
282 }\r
283\r
284 //\r
285 // Initilize FormSet Setting\r
286 //\r
287 LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));\r
288 ASSERT (LocalFormSet != NULL);\r
289 mSystemLevelFormSet = LocalFormSet;\r
290\r
291 ZeroMem (&ZeroGuid, sizeof (ZeroGuid));\r
292 Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet);\r
293 if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) {\r
294 DestroyFormSet (LocalFormSet);\r
295 continue;\r
296 }\r
297 InitializeCurrentSetting (LocalFormSet);\r
298\r
299 //\r
300 // Initilize Questions' Value\r
301 //\r
302 Status = LoadFormSetConfig (NULL, LocalFormSet);\r
303 if (EFI_ERROR (Status)) {\r
304 DestroyFormSet (LocalFormSet);\r
305 continue;\r
306 }\r
307 }\r
308\r
309 //\r
310 // Free resources, and restore gOldFormSet and gClassOfVfr\r
311 //\r
312 FreePool (HiiHandles);\r
313\r
314 gFinishRetrieveCall = OldRetrieveValue;\r
315 mSystemLevelFormSet = OldFormset;\r
316}\r
317\r
318/**\r
319 This is the routine which an external caller uses to direct the browser\r
320 where to obtain it's information.\r
321\r
322\r
323 @param This The Form Browser protocol instanse.\r
324 @param Handles A pointer to an array of Handles. If HandleCount > 1 we\r
325 display a list of the formsets for the handles specified.\r
326 @param HandleCount The number of Handles specified in Handle.\r
327 @param FormSetGuid This field points to the EFI_GUID which must match the Guid\r
328 field in the EFI_IFR_FORM_SET op-code for the specified\r
329 forms-based package. If FormSetGuid is NULL, then this\r
330 function will display the first found forms package.\r
331 @param FormId This field specifies which EFI_IFR_FORM to render as the first\r
332 displayable page. If this field has a value of 0x0000, then\r
333 the forms browser will render the specified forms in their encoded order.\r
334 @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in\r
335 characters.\r
336 @param ActionRequest Points to the action recommended by the form.\r
337\r
338 @retval EFI_SUCCESS The function completed successfully.\r
339 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
340 @retval EFI_NOT_FOUND No valid forms could be found to display.\r
341\r
342**/\r
343EFI_STATUS\r
344EFIAPI\r
345SendForm (\r
346 IN CONST EFI_FORM_BROWSER2_PROTOCOL *This,\r
347 IN EFI_HII_HANDLE *Handles,\r
348 IN UINTN HandleCount,\r
349 IN EFI_GUID *FormSetGuid, OPTIONAL\r
350 IN UINT16 FormId, OPTIONAL\r
351 IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL\r
352 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL\r
353 )\r
354{\r
355 EFI_STATUS Status;\r
356 UI_MENU_SELECTION *Selection;\r
357 UINTN Index;\r
358 FORM_BROWSER_FORMSET *FormSet;\r
359 FORM_ENTRY_INFO *MenuList;\r
360\r
361 //\r
362 // If EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found, return EFI_UNSUPPORTED.\r
363 //\r
364 if (mFormDisplay == NULL) {\r
365 return EFI_UNSUPPORTED;\r
366 }\r
367\r
368 //\r
369 // Save globals used by SendForm()\r
370 //\r
371 SaveBrowserContext ();\r
372\r
373 gFinishRetrieveCall = FALSE;\r
374 gResetRequired = FALSE;\r
375 gExitRequired = FALSE;\r
376 Status = EFI_SUCCESS;\r
377 gEmptyString = L"";\r
378 gDisplayFormData.ScreenDimensions = (EFI_SCREEN_DESCRIPTOR *) ScreenDimensions;\r
379\r
380 for (Index = 0; Index < HandleCount; Index++) {\r
381 Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION));\r
382 ASSERT (Selection != NULL);\r
383\r
384 Selection->Handle = Handles[Index];\r
385 if (FormSetGuid != NULL) {\r
386 CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));\r
387 Selection->FormId = FormId;\r
388 } else {\r
389 CopyMem (&Selection->FormSetGuid, &gEfiHiiPlatformSetupFormsetGuid, sizeof (EFI_GUID));\r
390 }\r
391\r
392 do {\r
393 FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));\r
394 ASSERT (FormSet != NULL);\r
395\r
396 //\r
397 // Initialize internal data structures of FormSet\r
398 //\r
399 Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet);\r
400 if (EFI_ERROR (Status) || IsListEmpty (&FormSet->FormListHead)) {\r
401 DestroyFormSet (FormSet);\r
402 break;\r
403 }\r
404 Selection->FormSet = FormSet;\r
405 mSystemLevelFormSet = FormSet;\r
406\r
407 //\r
408 // Display this formset\r
409 //\r
410 gCurrentSelection = Selection;\r
411\r
412 Status = SetupBrowser (Selection);\r
413\r
414 gCurrentSelection = NULL;\r
415 mSystemLevelFormSet = NULL;\r
416\r
417 //\r
418 // If no data is changed, don't need to save current FormSet into the maintain list.\r
419 //\r
420 if (!IsNvUpdateRequiredForFormSet (FormSet) && !IsStorageDataChangedForFormSet(FormSet)) {\r
421 CleanBrowserStorage(FormSet);\r
422 RemoveEntryList (&FormSet->Link);\r
423 DestroyFormSet (FormSet);\r
424 }\r
425\r
426 if (EFI_ERROR (Status)) {\r
427 break;\r
428 }\r
429 } while (Selection->Action == UI_ACTION_REFRESH_FORMSET);\r
430\r
431 FreePool (Selection);\r
432 }\r
433\r
434 //\r
435 // Still has error info, pop up a message.\r
436 //\r
437 if (gBrowserStatus != BROWSER_SUCCESS) {\r
438 gDisplayFormData.BrowserStatus = gBrowserStatus;\r
439 gDisplayFormData.ErrorString = gErrorInfo;\r
440\r
441 gBrowserStatus = BROWSER_SUCCESS;\r
442 gErrorInfo = NULL;\r
443\r
444 mFormDisplay->FormDisplay (&gDisplayFormData, NULL);\r
445 }\r
446\r
447 if (ActionRequest != NULL) {\r
448 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
449 if (gResetRequired) {\r
450 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;\r
451 }\r
452 }\r
453\r
454 mFormDisplay->ExitDisplay();\r
455\r
456 //\r
457 // Clear the menu history data.\r
458 //\r
459 while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {\r
460 MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);\r
461 RemoveEntryList (&MenuList->Link);\r
462 FreePool (MenuList);\r
463 }\r
464\r
465 //\r
466 // Restore globals used by SendForm()\r
467 //\r
468 RestoreBrowserContext ();\r
469\r
470 return Status;\r
471}\r
472\r
473/**\r
474 Get or set data to the storage.\r
475\r
476 @param ResultsDataSize The size of the buffer associatedwith ResultsData.\r
477 @param ResultsData A string returned from an IFR browser or\r
478 equivalent. The results string will have no\r
479 routing information in them.\r
480 @param RetrieveData A BOOLEAN field which allows an agent to retrieve\r
481 (if RetrieveData = TRUE) data from the uncommitted\r
482 browser state information or set (if RetrieveData\r
483 = FALSE) data in the uncommitted browser state\r
484 information.\r
485 @param Storage The pointer to the storage.\r
486\r
487 @retval EFI_SUCCESS The results have been distributed or are awaiting\r
488 distribution.\r
489\r
490**/\r
491EFI_STATUS \r
492ProcessStorage (\r
493 IN OUT UINTN *ResultsDataSize,\r
494 IN OUT EFI_STRING *ResultsData,\r
495 IN BOOLEAN RetrieveData,\r
496 IN BROWSER_STORAGE *Storage\r
497 )\r
498{\r
499 CHAR16 *ConfigResp;\r
500 EFI_STATUS Status;\r
501 CHAR16 *StrPtr;\r
502 UINTN BufferSize;\r
503 UINTN TmpSize;\r
504\r
505 if (RetrieveData) {\r
506 //\r
507 // Generate <ConfigResp>\r
508 //\r
509 Status = StorageToConfigResp (Storage, &ConfigResp, Storage->ConfigRequest, TRUE);\r
510 if (EFI_ERROR (Status)) {\r
511 return Status;\r
512 }\r
513\r
514 //\r
515 // Skip <ConfigHdr> and '&' to point to <ConfigBody> when first copy the configbody.\r
516 // Also need to consider add "\0" at first time.\r
517 //\r
518 StrPtr = ConfigResp + StrLen (Storage->ConfigHdr) + 1;\r
519 BufferSize = StrSize (StrPtr);\r
520\r
521\r
522 //\r
523 // Copy the data if the input buffer is bigger enough.\r
524 //\r
525 if (*ResultsDataSize >= BufferSize) {\r
526 StrCpy (*ResultsData, StrPtr);\r
527 }\r
528\r
529 *ResultsDataSize = BufferSize;\r
530 FreePool (ConfigResp);\r
531 } else {\r
532 //\r
533 // Prepare <ConfigResp>\r
534 //\r
535 TmpSize = StrLen (*ResultsData);\r
536 BufferSize = (TmpSize + StrLen (Storage->ConfigHdr) + 2) * sizeof (CHAR16);\r
537 ConfigResp = AllocateZeroPool (BufferSize);\r
538 ASSERT (ConfigResp != NULL);\r
539\r
540 StrCpy (ConfigResp, Storage->ConfigHdr);\r
541 StrCat (ConfigResp, L"&");\r
542 StrCat (ConfigResp, *ResultsData);\r
543\r
544 //\r
545 // Update Browser uncommited data\r
546 //\r
547 Status = ConfigRespToStorage (Storage, ConfigResp);\r
548 FreePool (ConfigResp);\r
549 if (EFI_ERROR (Status)) {\r
550 return Status;\r
551 }\r
552 }\r
553\r
554 return EFI_SUCCESS;\r
555}\r
556\r
557/**\r
558 This routine called this service in the browser to retrieve or set certain uncommitted \r
559 state information that resides in the open formsets. \r
560\r
561 @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL\r
562 instance.\r
563 @param ResultsDataSize A pointer to the size of the buffer associated\r
564 with ResultsData.\r
565 @param ResultsData A string returned from an IFR browser or\r
566 equivalent. The results string will have no\r
567 routing information in them.\r
568 @param RetrieveData A BOOLEAN field which allows an agent to retrieve\r
569 (if RetrieveData = TRUE) data from the uncommitted\r
570 browser state information or set (if RetrieveData\r
571 = FALSE) data in the uncommitted browser state\r
572 information.\r
573 @param VariableGuid An optional field to indicate the target variable\r
574 GUID name to use.\r
575 @param VariableName An optional field to indicate the target\r
576 human-readable variable name.\r
577\r
578 @retval EFI_SUCCESS The results have been distributed or are awaiting\r
579 distribution.\r
580 @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to\r
581 contain the results data.\r
582\r
583**/\r
584EFI_STATUS\r
585EFIAPI\r
586BrowserCallback (\r
587 IN CONST EFI_FORM_BROWSER2_PROTOCOL *This,\r
588 IN OUT UINTN *ResultsDataSize,\r
589 IN OUT EFI_STRING ResultsData,\r
590 IN BOOLEAN RetrieveData,\r
591 IN CONST EFI_GUID *VariableGuid, OPTIONAL\r
592 IN CONST CHAR16 *VariableName OPTIONAL\r
593 )\r
594{\r
595 EFI_STATUS Status;\r
596 LIST_ENTRY *Link;\r
597 BROWSER_STORAGE *Storage;\r
598 FORMSET_STORAGE *FormsetStorage;\r
599 UINTN TotalSize;\r
600 BOOLEAN Found;\r
601\r
602 if (ResultsDataSize == NULL || ResultsData == NULL) {\r
603 return EFI_INVALID_PARAMETER;\r
604 }\r
605\r
606 TotalSize = *ResultsDataSize;\r
607 Storage = NULL;\r
608 Found = FALSE;\r
609 Status = EFI_SUCCESS;\r
610\r
611 //\r
612 // If set browser data, pre load all hii formset to avoid set the varstore which is not \r
613 // saved in browser.\r
614 //\r
615 if (!RetrieveData && (gBrowserSettingScope == SystemLevel)) {\r
616 LoadAllHiiFormset();\r
617 }\r
618\r
619 if (VariableGuid != NULL) {\r
620 //\r
621 // Try to find target storage in the current formset.\r
622 //\r
623 Link = GetFirstNode (&gBrowserStorageList);\r
624 while (!IsNull (&gBrowserStorageList, Link)) {\r
625 Storage = BROWSER_STORAGE_FROM_LINK (Link);\r
626 Link = GetNextNode (&gBrowserStorageList, Link);\r
627 //\r
628 // Check the current storage.\r
629 //\r
630 if (!CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) {\r
631 continue;\r
632 }\r
633\r
634 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||\r
635 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
636 //\r
637 // Buffer storage require both GUID and Name\r
638 //\r
639 if (VariableName == NULL) {\r
640 return EFI_NOT_FOUND;\r
641 }\r
642\r
643 if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) {\r
644 continue;\r
645 }\r
646 }\r
647\r
648 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE ||\r
649 Storage->Type == EFI_HII_VARSTORE_BUFFER) {\r
650 if (mSystemLevelFormSet == NULL || mSystemLevelFormSet->HiiHandle == NULL) {\r
651 return EFI_NOT_FOUND;\r
652 }\r
653\r
654 if (Storage->HiiHandle != mSystemLevelFormSet->HiiHandle) {\r
655 continue;\r
656 }\r
657 }\r
658\r
659 Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, Storage);\r
660 if (EFI_ERROR (Status)) {\r
661 return Status;\r
662 }\r
663\r
664 //\r
665 // Different formsets may have same varstore, so here just set the flag\r
666 // not exit the circle.\r
667 // \r
668 Found = TRUE;\r
669 break;\r
670 }\r
671\r
672 if (!Found) {\r
673 return EFI_NOT_FOUND;\r
674 }\r
675 } else {\r
676 //\r
677 // GUID/Name is not specified, take the first storage in FormSet\r
678 //\r
679 if (mSystemLevelFormSet == NULL) {\r
680 return EFI_NOT_READY;\r
681 }\r
682\r
683 //\r
684 // Generate <ConfigResp>\r
685 //\r
686 Link = GetFirstNode (&mSystemLevelFormSet->StorageListHead);\r
687 if (IsNull (&mSystemLevelFormSet->StorageListHead, Link)) {\r
688 return EFI_UNSUPPORTED;\r
689 }\r
690\r
691 FormsetStorage = FORMSET_STORAGE_FROM_LINK (Link);\r
692 \r
693 Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, FormsetStorage->BrowserStorage);\r
694 if (EFI_ERROR (Status)) {\r
695 return Status;\r
696 }\r
697 }\r
698\r
699 if (RetrieveData) {\r
700 Status = TotalSize <= *ResultsDataSize ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;\r
701 *ResultsDataSize = TotalSize;\r
702 }\r
703 \r
704 return Status;\r
705\r
706}\r
707\r
708\r
709/**\r
710 Callback function for SimpleTextInEx protocol install events\r
711\r
712 @param Event the event that is signaled.\r
713 @param Context not used here.\r
714\r
715**/\r
716VOID\r
717EFIAPI\r
718FormDisplayCallback (\r
719 IN EFI_EVENT Event,\r
720 IN VOID *Context\r
721 )\r
722{\r
723 EFI_STATUS Status;\r
724\r
725 if (mFormDisplay != NULL) {\r
726 return;\r
727 }\r
728\r
729 Status = gBS->LocateProtocol (\r
730 &gEdkiiFormDisplayEngineProtocolGuid,\r
731 NULL,\r
732 (VOID **) &mFormDisplay\r
733 );\r
734}\r
735\r
736/**\r
737 Initialize Setup Browser driver.\r
738\r
739 @param ImageHandle The image handle.\r
740 @param SystemTable The system table.\r
741\r
742 @retval EFI_SUCCESS The Setup Browser module is initialized correctly..\r
743 @return Other value if failed to initialize the Setup Browser module.\r
744\r
745**/\r
746EFI_STATUS\r
747EFIAPI\r
748InitializeSetup (\r
749 IN EFI_HANDLE ImageHandle,\r
750 IN EFI_SYSTEM_TABLE *SystemTable\r
751 )\r
752{\r
753 EFI_STATUS Status;\r
754 VOID *Registration;\r
755\r
756 //\r
757 // Locate required Hii relative protocols\r
758 //\r
759 Status = gBS->LocateProtocol (\r
760 &gEfiHiiDatabaseProtocolGuid,\r
761 NULL,\r
762 (VOID **) &mHiiDatabase\r
763 );\r
764 ASSERT_EFI_ERROR (Status);\r
765\r
766 Status = gBS->LocateProtocol (\r
767 &gEfiHiiConfigRoutingProtocolGuid,\r
768 NULL,\r
769 (VOID **) &mHiiConfigRouting\r
770 );\r
771 ASSERT_EFI_ERROR (Status);\r
772\r
773 Status = gBS->LocateProtocol (\r
774 &gEfiDevicePathFromTextProtocolGuid,\r
775 NULL,\r
776 (VOID **) &mPathFromText\r
777 );\r
778\r
779 //\r
780 // Install FormBrowser2 protocol\r
781 //\r
782 mPrivateData.Handle = NULL;\r
783 Status = gBS->InstallProtocolInterface (\r
784 &mPrivateData.Handle,\r
785 &gEfiFormBrowser2ProtocolGuid,\r
786 EFI_NATIVE_INTERFACE,\r
787 &mPrivateData.FormBrowser2\r
788 );\r
789 ASSERT_EFI_ERROR (Status);\r
790\r
791 //\r
792 // Install FormBrowserEx2 protocol\r
793 //\r
794 InitializeListHead (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);\r
795 InitializeListHead (&mPrivateData.FormBrowserEx2.OverrideQestListHead);\r
796 mPrivateData.Handle = NULL;\r
797 Status = gBS->InstallProtocolInterface (\r
798 &mPrivateData.Handle,\r
799 &gEdkiiFormBrowserEx2ProtocolGuid,\r
800 EFI_NATIVE_INTERFACE,\r
801 &mPrivateData.FormBrowserEx2\r
802 );\r
803 ASSERT_EFI_ERROR (Status);\r
804 \r
805 Status = gBS->InstallProtocolInterface (\r
806 &mPrivateData.Handle,\r
807 &gEfiFormBrowserExProtocolGuid,\r
808 EFI_NATIVE_INTERFACE,\r
809 &mPrivateData.FormBrowserEx\r
810 );\r
811 ASSERT_EFI_ERROR (Status);\r
812\r
813 InitializeDisplayFormData ();\r
814\r
815 Status = gBS->LocateProtocol (\r
816 &gEdkiiFormDisplayEngineProtocolGuid,\r
817 NULL,\r
818 (VOID **) &mFormDisplay\r
819 );\r
820\r
821 if (EFI_ERROR (Status)) {\r
822 EfiCreateProtocolNotifyEvent (\r
823 &gEdkiiFormDisplayEngineProtocolGuid,\r
824 TPL_CALLBACK,\r
825 FormDisplayCallback,\r
826 NULL,\r
827 &Registration\r
828 );\r
829 }\r
830 \r
831 return EFI_SUCCESS;\r
832}\r
833\r
834\r
835/**\r
836 Create a new string in HII Package List.\r
837\r
838 @param String The String to be added\r
839 @param HiiHandle The package list in the HII database to insert the\r
840 specified string.\r
841\r
842 @return The output string.\r
843\r
844**/\r
845EFI_STRING_ID\r
846NewString (\r
847 IN CHAR16 *String,\r
848 IN EFI_HII_HANDLE HiiHandle\r
849 )\r
850{\r
851 EFI_STRING_ID StringId;\r
852\r
853 StringId = HiiSetString (HiiHandle, 0, String, NULL);\r
854 ASSERT (StringId != 0);\r
855\r
856 return StringId;\r
857}\r
858\r
859\r
860/**\r
861 Delete a string from HII Package List.\r
862\r
863 @param StringId Id of the string in HII database.\r
864 @param HiiHandle The HII package list handle.\r
865\r
866 @retval EFI_SUCCESS The string was deleted successfully.\r
867\r
868**/\r
869EFI_STATUS\r
870DeleteString (\r
871 IN EFI_STRING_ID StringId,\r
872 IN EFI_HII_HANDLE HiiHandle\r
873 )\r
874{\r
875 CHAR16 NullChar;\r
876\r
877 NullChar = CHAR_NULL;\r
878 HiiSetString (HiiHandle, StringId, &NullChar, NULL);\r
879 return EFI_SUCCESS;\r
880}\r
881\r
882\r
883/**\r
884 Get the string based on the StringId and HII Package List Handle.\r
885\r
886 @param Token The String's ID.\r
887 @param HiiHandle The package list in the HII database to search for\r
888 the specified string.\r
889\r
890 @return The output string.\r
891\r
892**/\r
893CHAR16 *\r
894GetToken (\r
895 IN EFI_STRING_ID Token,\r
896 IN EFI_HII_HANDLE HiiHandle\r
897 )\r
898{\r
899 EFI_STRING String;\r
900\r
901 if (HiiHandle == NULL) {\r
902 return NULL;\r
903 }\r
904\r
905 String = HiiGetString (HiiHandle, Token, NULL);\r
906 if (String == NULL) {\r
907 String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString);\r
908 ASSERT (String != NULL);\r
909 }\r
910 return (CHAR16 *) String;\r
911}\r
912\r
913\r
914/**\r
915 Allocate new memory and then copy the Unicode string Source to Destination.\r
916\r
917 @param Dest Location to copy string\r
918 @param Src String to copy\r
919\r
920**/\r
921VOID\r
922NewStringCpy (\r
923 IN OUT CHAR16 **Dest,\r
924 IN CHAR16 *Src\r
925 )\r
926{\r
927 if (*Dest != NULL) {\r
928 FreePool (*Dest);\r
929 }\r
930 *Dest = AllocateCopyPool (StrSize (Src), Src);\r
931 ASSERT (*Dest != NULL);\r
932}\r
933\r
934\r
935/**\r
936 Allocate new memory and concatinate Source on the end of Destination.\r
937\r
938 @param Dest String to added to the end of.\r
939 @param Src String to concatinate.\r
940\r
941**/\r
942VOID\r
943NewStringCat (\r
944 IN OUT CHAR16 **Dest,\r
945 IN CHAR16 *Src\r
946 )\r
947{\r
948 CHAR16 *NewString;\r
949 UINTN TmpSize;\r
950\r
951 if (*Dest == NULL) {\r
952 NewStringCpy (Dest, Src);\r
953 return;\r
954 }\r
955\r
956 TmpSize = StrSize (*Dest);\r
957 NewString = AllocateZeroPool (TmpSize + StrSize (Src) - 1);\r
958 ASSERT (NewString != NULL);\r
959\r
960 StrCpy (NewString, *Dest);\r
961 StrCat (NewString, Src);\r
962\r
963 FreePool (*Dest);\r
964 *Dest = NewString;\r
965}\r
966\r
967/**\r
968 Get Value for given Name from a NameValue Storage.\r
969\r
970 @param Storage The NameValue Storage.\r
971 @param Name The Name.\r
972 @param Value The retured Value.\r
973 @param GetValueFrom Where to get source value, from EditValue or Value.\r
974\r
975 @retval EFI_SUCCESS Value found for given Name.\r
976 @retval EFI_NOT_FOUND No such Name found in NameValue storage.\r
977\r
978**/\r
979EFI_STATUS\r
980GetValueByName (\r
981 IN BROWSER_STORAGE *Storage,\r
982 IN CHAR16 *Name,\r
983 IN OUT CHAR16 **Value,\r
984 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom\r
985 )\r
986{\r
987 LIST_ENTRY *Link;\r
988 NAME_VALUE_NODE *Node;\r
989\r
990 if (GetValueFrom != GetSetValueWithEditBuffer && GetValueFrom != GetSetValueWithBuffer) {\r
991 return EFI_INVALID_PARAMETER;\r
992 }\r
993\r
994 *Value = NULL;\r
995\r
996 Link = GetFirstNode (&Storage->NameValueListHead);\r
997 while (!IsNull (&Storage->NameValueListHead, Link)) {\r
998 Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
999\r
1000 if (StrCmp (Name, Node->Name) == 0) {\r
1001 if (GetValueFrom == GetSetValueWithEditBuffer) {\r
1002 NewStringCpy (Value, Node->EditValue);\r
1003 } else {\r
1004 NewStringCpy (Value, Node->Value);\r
1005 }\r
1006 return EFI_SUCCESS;\r
1007 }\r
1008\r
1009 Link = GetNextNode (&Storage->NameValueListHead, Link);\r
1010 }\r
1011\r
1012 return EFI_NOT_FOUND;\r
1013}\r
1014\r
1015\r
1016/**\r
1017 Set Value of given Name in a NameValue Storage.\r
1018\r
1019 @param Storage The NameValue Storage.\r
1020 @param Name The Name.\r
1021 @param Value The Value to set.\r
1022 @param SetValueTo Whether update editValue or Value.\r
1023 @param ReturnNode The node use the input name.\r
1024\r
1025 @retval EFI_SUCCESS Value found for given Name.\r
1026 @retval EFI_NOT_FOUND No such Name found in NameValue storage.\r
1027\r
1028**/\r
1029EFI_STATUS\r
1030SetValueByName (\r
1031 IN BROWSER_STORAGE *Storage,\r
1032 IN CHAR16 *Name,\r
1033 IN CHAR16 *Value,\r
1034 IN GET_SET_QUESTION_VALUE_WITH SetValueTo,\r
1035 OUT NAME_VALUE_NODE **ReturnNode\r
1036 )\r
1037{\r
1038 LIST_ENTRY *Link;\r
1039 NAME_VALUE_NODE *Node;\r
1040 CHAR16 *Buffer;\r
1041\r
1042 if (SetValueTo != GetSetValueWithEditBuffer && SetValueTo != GetSetValueWithBuffer) {\r
1043 return EFI_INVALID_PARAMETER;\r
1044 }\r
1045\r
1046 Link = GetFirstNode (&Storage->NameValueListHead);\r
1047 while (!IsNull (&Storage->NameValueListHead, Link)) {\r
1048 Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
1049\r
1050 if (StrCmp (Name, Node->Name) == 0) {\r
1051 if (SetValueTo == GetSetValueWithEditBuffer) {\r
1052 Buffer = Node->EditValue;\r
1053 } else {\r
1054 Buffer = Node->Value;\r
1055 }\r
1056 if (Buffer != NULL) {\r
1057 FreePool (Buffer);\r
1058 }\r
1059 Buffer = AllocateCopyPool (StrSize (Value), Value);\r
1060 ASSERT (Buffer != NULL);\r
1061 if (SetValueTo == GetSetValueWithEditBuffer) {\r
1062 Node->EditValue = Buffer;\r
1063 } else {\r
1064 Node->Value = Buffer;\r
1065 }\r
1066\r
1067 if (ReturnNode != NULL) {\r
1068 *ReturnNode = Node;\r
1069 }\r
1070\r
1071 return EFI_SUCCESS;\r
1072 }\r
1073\r
1074 Link = GetNextNode (&Storage->NameValueListHead, Link);\r
1075 }\r
1076\r
1077 return EFI_NOT_FOUND;\r
1078}\r
1079\r
1080\r
1081/**\r
1082 Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>.\r
1083\r
1084 @param Storage The Storage to be conveted.\r
1085 @param ConfigResp The returned <ConfigResp>.\r
1086 @param ConfigRequest The ConfigRequest string.\r
1087 @param GetEditBuf Get the data from editbuffer or buffer.\r
1088\r
1089 @retval EFI_SUCCESS Convert success.\r
1090 @retval EFI_INVALID_PARAMETER Incorrect storage type.\r
1091\r
1092**/\r
1093EFI_STATUS\r
1094StorageToConfigResp (\r
1095 IN BROWSER_STORAGE *Storage,\r
1096 IN CHAR16 **ConfigResp,\r
1097 IN CHAR16 *ConfigRequest,\r
1098 IN BOOLEAN GetEditBuf\r
1099 )\r
1100{\r
1101 EFI_STATUS Status;\r
1102 EFI_STRING Progress;\r
1103 LIST_ENTRY *Link;\r
1104 NAME_VALUE_NODE *Node;\r
1105 UINT8 *SourceBuf;\r
1106\r
1107 Status = EFI_SUCCESS;\r
1108\r
1109 switch (Storage->Type) {\r
1110 case EFI_HII_VARSTORE_BUFFER:\r
1111 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:\r
1112 SourceBuf = GetEditBuf ? Storage->EditBuffer : Storage->Buffer;\r
1113 Status = mHiiConfigRouting->BlockToConfig (\r
1114 mHiiConfigRouting,\r
1115 ConfigRequest,\r
1116 SourceBuf,\r
1117 Storage->Size,\r
1118 ConfigResp,\r
1119 &Progress\r
1120 );\r
1121 break;\r
1122\r
1123 case EFI_HII_VARSTORE_NAME_VALUE:\r
1124 *ConfigResp = NULL;\r
1125 NewStringCat (ConfigResp, Storage->ConfigHdr);\r
1126\r
1127 Link = GetFirstNode (&Storage->NameValueListHead);\r
1128 while (!IsNull (&Storage->NameValueListHead, Link)) {\r
1129 Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
1130\r
1131 if (StrStr (ConfigRequest, Node->Name) != NULL) {\r
1132 NewStringCat (ConfigResp, L"&");\r
1133 NewStringCat (ConfigResp, Node->Name);\r
1134 NewStringCat (ConfigResp, L"=");\r
1135 if (GetEditBuf) {\r
1136 NewStringCat (ConfigResp, Node->EditValue);\r
1137 } else {\r
1138 NewStringCat (ConfigResp, Node->Value);\r
1139 }\r
1140 }\r
1141 Link = GetNextNode (&Storage->NameValueListHead, Link);\r
1142 }\r
1143 break;\r
1144\r
1145 case EFI_HII_VARSTORE_EFI_VARIABLE:\r
1146 default:\r
1147 Status = EFI_INVALID_PARAMETER;\r
1148 break;\r
1149 }\r
1150\r
1151 return Status;\r
1152}\r
1153\r
1154\r
1155/**\r
1156 Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage.\r
1157\r
1158 @param Storage The Storage to receive the settings.\r
1159 @param ConfigResp The <ConfigResp> to be converted.\r
1160\r
1161 @retval EFI_SUCCESS Convert success.\r
1162 @retval EFI_INVALID_PARAMETER Incorrect storage type.\r
1163\r
1164**/\r
1165EFI_STATUS\r
1166ConfigRespToStorage (\r
1167 IN BROWSER_STORAGE *Storage,\r
1168 IN CHAR16 *ConfigResp\r
1169 )\r
1170{\r
1171 EFI_STATUS Status;\r
1172 EFI_STRING Progress;\r
1173 UINTN BufferSize;\r
1174 CHAR16 *StrPtr;\r
1175 CHAR16 *Name;\r
1176 CHAR16 *Value;\r
1177\r
1178 Status = EFI_SUCCESS;\r
1179\r
1180 switch (Storage->Type) {\r
1181 case EFI_HII_VARSTORE_BUFFER:\r
1182 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:\r
1183 BufferSize = Storage->Size;\r
1184 Status = mHiiConfigRouting->ConfigToBlock (\r
1185 mHiiConfigRouting,\r
1186 ConfigResp,\r
1187 Storage->EditBuffer,\r
1188 &BufferSize,\r
1189 &Progress\r
1190 );\r
1191 break;\r
1192\r
1193 case EFI_HII_VARSTORE_NAME_VALUE:\r
1194 StrPtr = StrStr (ConfigResp, L"PATH");\r
1195 if (StrPtr == NULL) {\r
1196 break;\r
1197 }\r
1198 StrPtr = StrStr (ConfigResp, L"&");\r
1199 while (StrPtr != NULL) {\r
1200 //\r
1201 // Skip '&'\r
1202 //\r
1203 StrPtr = StrPtr + 1;\r
1204 Name = StrPtr;\r
1205 StrPtr = StrStr (StrPtr, L"=");\r
1206 if (StrPtr == NULL) {\r
1207 break;\r
1208 }\r
1209 *StrPtr = 0;\r
1210\r
1211 //\r
1212 // Skip '='\r
1213 //\r
1214 StrPtr = StrPtr + 1;\r
1215 Value = StrPtr;\r
1216 StrPtr = StrStr (StrPtr, L"&");\r
1217 if (StrPtr != NULL) {\r
1218 *StrPtr = 0;\r
1219 }\r
1220 SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer, NULL);\r
1221 }\r
1222 break;\r
1223\r
1224 case EFI_HII_VARSTORE_EFI_VARIABLE:\r
1225 default:\r
1226 Status = EFI_INVALID_PARAMETER;\r
1227 break;\r
1228 }\r
1229\r
1230 return Status;\r
1231}\r
1232\r
1233\r
1234/**\r
1235 Get Question's current Value.\r
1236\r
1237 @param FormSet FormSet data structure.\r
1238 @param Form Form data structure.\r
1239 @param Question Question to be initialized.\r
1240 @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.\r
1241\r
1242 @retval EFI_SUCCESS The function completed successfully.\r
1243\r
1244**/\r
1245EFI_STATUS\r
1246GetQuestionValue (\r
1247 IN FORM_BROWSER_FORMSET *FormSet,\r
1248 IN FORM_BROWSER_FORM *Form,\r
1249 IN OUT FORM_BROWSER_STATEMENT *Question,\r
1250 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom\r
1251 )\r
1252{\r
1253 EFI_STATUS Status;\r
1254 BOOLEAN Enabled;\r
1255 BOOLEAN Pending;\r
1256 UINT8 *Dst;\r
1257 UINTN StorageWidth;\r
1258 EFI_TIME EfiTime;\r
1259 BROWSER_STORAGE *Storage;\r
1260 EFI_IFR_TYPE_VALUE *QuestionValue;\r
1261 CHAR16 *ConfigRequest;\r
1262 CHAR16 *Progress;\r
1263 CHAR16 *Result;\r
1264 CHAR16 *Value;\r
1265 CHAR16 *StringPtr;\r
1266 UINTN Length;\r
1267 UINTN Index;\r
1268 UINTN LengthStr;\r
1269 BOOLEAN IsBufferStorage;\r
1270 BOOLEAN IsString;\r
1271 CHAR16 TemStr[5];\r
1272 UINT8 DigitUint8;\r
1273\r
1274 Status = EFI_SUCCESS;\r
1275 Value = NULL;\r
1276 Result = NULL;\r
1277\r
1278 if (GetValueFrom >= GetSetValueWithMax) {\r
1279 return EFI_INVALID_PARAMETER;\r
1280 }\r
1281\r
1282 //\r
1283 // Question value is provided by an Expression, evaluate it\r
1284 //\r
1285 if (Question->ValueExpression != NULL) {\r
1286 Status = EvaluateExpression (FormSet, Form, Question->ValueExpression);\r
1287 if (!EFI_ERROR (Status)) {\r
1288 if (Question->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {\r
1289 ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);\r
1290 if (Question->StorageWidth > Question->ValueExpression->Result.BufferLen) {\r
1291 CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->ValueExpression->Result.BufferLen);\r
1292 Question->HiiValue.BufferLen = Question->ValueExpression->Result.BufferLen;\r
1293 } else {\r
1294 CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->StorageWidth);\r
1295 Question->HiiValue.BufferLen = Question->StorageWidth;\r
1296 }\r
1297 FreePool (Question->ValueExpression->Result.Buffer);\r
1298 }\r
1299 Question->HiiValue.Type = Question->ValueExpression->Result.Type;\r
1300 CopyMem (&Question->HiiValue.Value, &Question->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE)); \r
1301 }\r
1302 return Status;\r
1303 }\r
1304 \r
1305 //\r
1306 // Get question value by read expression.\r
1307 //\r
1308 if (Question->ReadExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {\r
1309 Status = EvaluateExpression (FormSet, Form, Question->ReadExpression);\r
1310 if (!EFI_ERROR (Status) && \r
1311 ((Question->ReadExpression->Result.Type < EFI_IFR_TYPE_OTHER) || (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER))) {\r
1312 //\r
1313 // Only update question value to the valid result.\r
1314 //\r
1315 if (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {\r
1316 ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);\r
1317 if (Question->StorageWidth > Question->ReadExpression->Result.BufferLen) {\r
1318 CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->ReadExpression->Result.BufferLen);\r
1319 Question->HiiValue.BufferLen = Question->ReadExpression->Result.BufferLen;\r
1320 } else {\r
1321 CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->StorageWidth);\r
1322 Question->HiiValue.BufferLen = Question->StorageWidth;\r
1323 }\r
1324 FreePool (Question->ReadExpression->Result.Buffer);\r
1325 }\r
1326 Question->HiiValue.Type = Question->ReadExpression->Result.Type;\r
1327 CopyMem (&Question->HiiValue.Value, &Question->ReadExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE)); \r
1328 return EFI_SUCCESS;\r
1329 }\r
1330 }\r
1331\r
1332 //\r
1333 // Question value is provided by RTC\r
1334 //\r
1335 Storage = Question->Storage;\r
1336 QuestionValue = &Question->HiiValue.Value;\r
1337 if (Storage == NULL) {\r
1338 //\r
1339 // It's a Question without storage, or RTC date/time\r
1340 //\r
1341 if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {\r
1342 //\r
1343 // Date and time define the same Flags bit\r
1344 //\r
1345 switch (Question->Flags & EFI_QF_DATE_STORAGE) {\r
1346 case QF_DATE_STORAGE_TIME:\r
1347 Status = gRT->GetTime (&EfiTime, NULL);\r
1348 break;\r
1349\r
1350 case QF_DATE_STORAGE_WAKEUP:\r
1351 Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);\r
1352 break;\r
1353\r
1354 case QF_DATE_STORAGE_NORMAL:\r
1355 default:\r
1356 //\r
1357 // For date/time without storage\r
1358 //\r
1359 return EFI_SUCCESS;\r
1360 }\r
1361\r
1362 if (EFI_ERROR (Status)) {\r
1363 return Status;\r
1364 }\r
1365\r
1366 if (Question->Operand == EFI_IFR_DATE_OP) {\r
1367 QuestionValue->date.Year = EfiTime.Year;\r
1368 QuestionValue->date.Month = EfiTime.Month;\r
1369 QuestionValue->date.Day = EfiTime.Day;\r
1370 } else {\r
1371 QuestionValue->time.Hour = EfiTime.Hour;\r
1372 QuestionValue->time.Minute = EfiTime.Minute;\r
1373 QuestionValue->time.Second = EfiTime.Second;\r
1374 }\r
1375 }\r
1376\r
1377 return EFI_SUCCESS;\r
1378 }\r
1379\r
1380 //\r
1381 // Question value is provided by EFI variable\r
1382 //\r
1383 StorageWidth = Question->StorageWidth;\r
1384 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
1385 if (Question->BufferValue != NULL) {\r
1386 Dst = Question->BufferValue;\r
1387 } else {\r
1388 Dst = (UINT8 *) QuestionValue;\r
1389 }\r
1390\r
1391 Status = gRT->GetVariable (\r
1392 Question->VariableName,\r
1393 &Storage->Guid,\r
1394 NULL,\r
1395 &StorageWidth,\r
1396 Dst\r
1397 );\r
1398 //\r
1399 // Always return success, even this EFI variable doesn't exist\r
1400 //\r
1401 return EFI_SUCCESS;\r
1402 }\r
1403\r
1404 //\r
1405 // Question Value is provided by Buffer Storage or NameValue Storage\r
1406 //\r
1407 if (Question->BufferValue != NULL) {\r
1408 //\r
1409 // This Question is password or orderedlist\r
1410 //\r
1411 Dst = Question->BufferValue;\r
1412 } else {\r
1413 //\r
1414 // Other type of Questions\r
1415 //\r
1416 Dst = (UINT8 *) &Question->HiiValue.Value;\r
1417 }\r
1418\r
1419 if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
1420 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
1421 IsBufferStorage = TRUE;\r
1422 } else {\r
1423 IsBufferStorage = FALSE;\r
1424 }\r
1425 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);\r
1426 if (GetValueFrom == GetSetValueWithEditBuffer || GetValueFrom == GetSetValueWithBuffer ) {\r
1427 if (IsBufferStorage) {\r
1428 if (GetValueFrom == GetSetValueWithEditBuffer) {\r
1429 //\r
1430 // Copy from storage Edit buffer\r
1431 //\r
1432 CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);\r
1433 } else {\r
1434 //\r
1435 // Copy from storage Edit buffer\r
1436 //\r
1437 CopyMem (Dst, Storage->Buffer + Question->VarStoreInfo.VarOffset, StorageWidth);\r
1438 }\r
1439 } else {\r
1440 Value = NULL;\r
1441 Status = GetValueByName (Storage, Question->VariableName, &Value, GetValueFrom);\r
1442 if (EFI_ERROR (Status)) {\r
1443 return Status;\r
1444 }\r
1445\r
1446 ASSERT (Value != NULL);\r
1447 LengthStr = StrLen (Value);\r
1448 Status = EFI_SUCCESS;\r
1449 if (IsString) {\r
1450 //\r
1451 // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"\r
1452 // Add string tail char L'\0' into Length\r
1453 //\r
1454 Length = StorageWidth + sizeof (CHAR16);\r
1455 if (Length < ((LengthStr / 4 + 1) * 2)) {\r
1456 Status = EFI_BUFFER_TOO_SMALL;\r
1457 } else {\r
1458 StringPtr = (CHAR16 *) Dst;\r
1459 ZeroMem (TemStr, sizeof (TemStr));\r
1460 for (Index = 0; Index < LengthStr; Index += 4) {\r
1461 StrnCpy (TemStr, Value + Index, 4);\r
1462 StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);\r
1463 }\r
1464 //\r
1465 // Add tailing L'\0' character\r
1466 //\r
1467 StringPtr[Index/4] = L'\0';\r
1468 }\r
1469 } else {\r
1470 if (StorageWidth < ((LengthStr + 1) / 2)) {\r
1471 Status = EFI_BUFFER_TOO_SMALL;\r
1472 } else {\r
1473 ZeroMem (TemStr, sizeof (TemStr));\r
1474 for (Index = 0; Index < LengthStr; Index ++) {\r
1475 TemStr[0] = Value[LengthStr - Index - 1];\r
1476 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
1477 if ((Index & 1) == 0) {\r
1478 Dst [Index/2] = DigitUint8;\r
1479 } else {\r
1480 Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);\r
1481 }\r
1482 }\r
1483 }\r
1484 }\r
1485\r
1486 FreePool (Value);\r
1487 }\r
1488 } else {\r
1489 //\r
1490 // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||\r
1491 // <ConfigHdr> + "&" + <VariableName>\r
1492 //\r
1493 if (IsBufferStorage) {\r
1494 Length = StrLen (Storage->ConfigHdr);\r
1495 Length += StrLen (Question->BlockName);\r
1496 } else {\r
1497 Length = StrLen (Storage->ConfigHdr);\r
1498 Length += StrLen (Question->VariableName) + 1;\r
1499 }\r
1500 ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));\r
1501 ASSERT (ConfigRequest != NULL);\r
1502\r
1503 StrCpy (ConfigRequest, Storage->ConfigHdr);\r
1504 if (IsBufferStorage) {\r
1505 StrCat (ConfigRequest, Question->BlockName);\r
1506 } else {\r
1507 StrCat (ConfigRequest, L"&");\r
1508 StrCat (ConfigRequest, Question->VariableName);\r
1509 }\r
1510\r
1511 //\r
1512 // Request current settings from Configuration Driver\r
1513 //\r
1514 Status = mHiiConfigRouting->ExtractConfig (\r
1515 mHiiConfigRouting,\r
1516 ConfigRequest,\r
1517 &Progress,\r
1518 &Result\r
1519 );\r
1520 FreePool (ConfigRequest);\r
1521 if (EFI_ERROR (Status)) {\r
1522 return Status;\r
1523 }\r
1524\r
1525 //\r
1526 // Skip <ConfigRequest>\r
1527 //\r
1528 if (IsBufferStorage) {\r
1529 Value = StrStr (Result, L"&VALUE");\r
1530 if (Value == NULL) {\r
1531 FreePool (Result);\r
1532 return EFI_NOT_FOUND;\r
1533 }\r
1534 //\r
1535 // Skip "&VALUE"\r
1536 //\r
1537 Value = Value + 6;\r
1538 } else {\r
1539 Value = Result + Length;\r
1540 }\r
1541 if (*Value != '=') {\r
1542 FreePool (Result);\r
1543 return EFI_NOT_FOUND;\r
1544 }\r
1545 //\r
1546 // Skip '=', point to value\r
1547 //\r
1548 Value = Value + 1;\r
1549\r
1550 //\r
1551 // Suppress <AltResp> if any\r
1552 //\r
1553 StringPtr = Value;\r
1554 while (*StringPtr != L'\0' && *StringPtr != L'&') {\r
1555 StringPtr++;\r
1556 }\r
1557 *StringPtr = L'\0';\r
1558\r
1559 LengthStr = StrLen (Value);\r
1560 Status = EFI_SUCCESS;\r
1561 if (!IsBufferStorage && IsString) {\r
1562 //\r
1563 // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"\r
1564 // Add string tail char L'\0' into Length\r
1565 //\r
1566 Length = StorageWidth + sizeof (CHAR16);\r
1567 if (Length < ((LengthStr / 4 + 1) * 2)) {\r
1568 Status = EFI_BUFFER_TOO_SMALL;\r
1569 } else {\r
1570 StringPtr = (CHAR16 *) Dst;\r
1571 ZeroMem (TemStr, sizeof (TemStr));\r
1572 for (Index = 0; Index < LengthStr; Index += 4) {\r
1573 StrnCpy (TemStr, Value + Index, 4);\r
1574 StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);\r
1575 }\r
1576 //\r
1577 // Add tailing L'\0' character\r
1578 //\r
1579 StringPtr[Index/4] = L'\0';\r
1580 }\r
1581 } else {\r
1582 if (StorageWidth < ((LengthStr + 1) / 2)) {\r
1583 Status = EFI_BUFFER_TOO_SMALL;\r
1584 } else {\r
1585 ZeroMem (TemStr, sizeof (TemStr));\r
1586 for (Index = 0; Index < LengthStr; Index ++) {\r
1587 TemStr[0] = Value[LengthStr - Index - 1];\r
1588 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
1589 if ((Index & 1) == 0) {\r
1590 Dst [Index/2] = DigitUint8;\r
1591 } else {\r
1592 Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);\r
1593 }\r
1594 }\r
1595 }\r
1596 }\r
1597\r
1598 if (EFI_ERROR (Status)) {\r
1599 FreePool (Result);\r
1600 return Status;\r
1601 }\r
1602\r
1603 //\r
1604 // Synchronize Edit Buffer\r
1605 //\r
1606 if (IsBufferStorage) {\r
1607 CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);\r
1608 } else {\r
1609 SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer, NULL);\r
1610 }\r
1611\r
1612 if (Result != NULL) {\r
1613 FreePool (Result);\r
1614 }\r
1615 }\r
1616\r
1617 return Status;\r
1618}\r
1619\r
1620\r
1621/**\r
1622 Save Question Value to edit copy(cached) or Storage(uncached).\r
1623\r
1624 @param FormSet FormSet data structure.\r
1625 @param Form Form data structure.\r
1626 @param Question Pointer to the Question.\r
1627 @param SetValueTo Update the question value to editbuffer , buffer or hii driver.\r
1628\r
1629 @retval EFI_SUCCESS The function completed successfully.\r
1630\r
1631**/\r
1632EFI_STATUS\r
1633SetQuestionValue (\r
1634 IN FORM_BROWSER_FORMSET *FormSet,\r
1635 IN FORM_BROWSER_FORM *Form,\r
1636 IN OUT FORM_BROWSER_STATEMENT *Question,\r
1637 IN GET_SET_QUESTION_VALUE_WITH SetValueTo\r
1638 )\r
1639{\r
1640 EFI_STATUS Status;\r
1641 BOOLEAN Enabled;\r
1642 BOOLEAN Pending;\r
1643 UINT8 *Src;\r
1644 EFI_TIME EfiTime;\r
1645 UINTN BufferLen;\r
1646 UINTN StorageWidth;\r
1647 BROWSER_STORAGE *Storage;\r
1648 EFI_IFR_TYPE_VALUE *QuestionValue;\r
1649 CHAR16 *ConfigResp;\r
1650 CHAR16 *Progress;\r
1651 CHAR16 *Value;\r
1652 UINTN Length;\r
1653 BOOLEAN IsBufferStorage;\r
1654 BOOLEAN IsString;\r
1655 UINT8 *TemBuffer;\r
1656 CHAR16 *TemName;\r
1657 CHAR16 *TemString;\r
1658 UINTN Index;\r
1659 NAME_VALUE_NODE *Node;\r
1660\r
1661 Status = EFI_SUCCESS;\r
1662 Node = NULL;\r
1663\r
1664 if (SetValueTo >= GetSetValueWithMax) {\r
1665 return EFI_INVALID_PARAMETER;\r
1666 }\r
1667\r
1668 //\r
1669 // If Question value is provided by an Expression, then it is read only\r
1670 //\r
1671 if (Question->ValueExpression != NULL) {\r
1672 return Status;\r
1673 }\r
1674 \r
1675 //\r
1676 // Before set question value, evaluate its write expression.\r
1677 //\r
1678 if (Question->WriteExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {\r
1679 Status = EvaluateExpression (FormSet, Form, Question->WriteExpression);\r
1680 if (EFI_ERROR (Status)) {\r
1681 return Status;\r
1682 }\r
1683 }\r
1684\r
1685 //\r
1686 // Question value is provided by RTC\r
1687 //\r
1688 Storage = Question->Storage;\r
1689 QuestionValue = &Question->HiiValue.Value;\r
1690 if (Storage == NULL) {\r
1691 //\r
1692 // It's a Question without storage, or RTC date/time\r
1693 //\r
1694 if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {\r
1695 //\r
1696 // Date and time define the same Flags bit\r
1697 //\r
1698 switch (Question->Flags & EFI_QF_DATE_STORAGE) {\r
1699 case QF_DATE_STORAGE_TIME:\r
1700 Status = gRT->GetTime (&EfiTime, NULL);\r
1701 break;\r
1702\r
1703 case QF_DATE_STORAGE_WAKEUP:\r
1704 Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);\r
1705 break;\r
1706\r
1707 case QF_DATE_STORAGE_NORMAL:\r
1708 default:\r
1709 //\r
1710 // For date/time without storage\r
1711 //\r
1712 return EFI_SUCCESS;\r
1713 }\r
1714\r
1715 if (EFI_ERROR (Status)) {\r
1716 return Status;\r
1717 }\r
1718\r
1719 if (Question->Operand == EFI_IFR_DATE_OP) {\r
1720 EfiTime.Year = QuestionValue->date.Year;\r
1721 EfiTime.Month = QuestionValue->date.Month;\r
1722 EfiTime.Day = QuestionValue->date.Day;\r
1723 } else {\r
1724 EfiTime.Hour = QuestionValue->time.Hour;\r
1725 EfiTime.Minute = QuestionValue->time.Minute;\r
1726 EfiTime.Second = QuestionValue->time.Second;\r
1727 }\r
1728\r
1729 if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) {\r
1730 Status = gRT->SetTime (&EfiTime);\r
1731 } else {\r
1732 Status = gRT->SetWakeupTime (TRUE, &EfiTime);\r
1733 }\r
1734 }\r
1735\r
1736 return Status;\r
1737 }\r
1738\r
1739 //\r
1740 // Question value is provided by EFI variable\r
1741 //\r
1742 StorageWidth = Question->StorageWidth;\r
1743 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
1744 if (Question->BufferValue != NULL) {\r
1745 Src = Question->BufferValue;\r
1746 } else {\r
1747 Src = (UINT8 *) QuestionValue;\r
1748 }\r
1749\r
1750 Status = gRT->SetVariable (\r
1751 Question->VariableName,\r
1752 &Storage->Guid,\r
1753 Storage->Attributes,\r
1754 StorageWidth,\r
1755 Src\r
1756 );\r
1757 return Status;\r
1758 }\r
1759\r
1760 //\r
1761 // Question Value is provided by Buffer Storage or NameValue Storage\r
1762 //\r
1763 if (Question->BufferValue != NULL) {\r
1764 Src = Question->BufferValue;\r
1765 } else {\r
1766 Src = (UINT8 *) &Question->HiiValue.Value;\r
1767 }\r
1768\r
1769 if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
1770 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
1771 IsBufferStorage = TRUE;\r
1772 } else {\r
1773 IsBufferStorage = FALSE;\r
1774 }\r
1775 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);\r
1776\r
1777 if (SetValueTo == GetSetValueWithEditBuffer || SetValueTo == GetSetValueWithBuffer) {\r
1778 if (IsBufferStorage) {\r
1779 if (SetValueTo == GetSetValueWithEditBuffer) {\r
1780 //\r
1781 // Copy to storage edit buffer\r
1782 // \r
1783 CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);\r
1784 } else if (SetValueTo == GetSetValueWithBuffer) {\r
1785 //\r
1786 // Copy to storage edit buffer\r
1787 // \r
1788 CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);\r
1789 }\r
1790 //\r
1791 // Check whether question value has been changed.\r
1792 //\r
1793 if (CompareMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth) != 0) {\r
1794 Question->ValueChanged = TRUE;\r
1795 } else {\r
1796 Question->ValueChanged = FALSE;\r
1797 }\r
1798 } else {\r
1799 if (IsString) {\r
1800 //\r
1801 // Allocate enough string buffer.\r
1802 //\r
1803 Value = NULL;\r
1804 BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);\r
1805 Value = AllocateZeroPool (BufferLen);\r
1806 ASSERT (Value != NULL);\r
1807 //\r
1808 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"\r
1809 //\r
1810 TemName = (CHAR16 *) Src;\r
1811 TemString = Value;\r
1812 for (; *TemName != L'\0'; TemName++) {\r
1813 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);\r
1814 }\r
1815 } else {\r
1816 BufferLen = StorageWidth * 2 + 1;\r
1817 Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));\r
1818 ASSERT (Value != NULL);\r
1819 //\r
1820 // Convert Buffer to Hex String\r
1821 //\r
1822 TemBuffer = Src + StorageWidth - 1;\r
1823 TemString = Value;\r
1824 for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {\r
1825 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);\r
1826 }\r
1827 }\r
1828\r
1829 Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo, &Node);\r
1830 FreePool (Value);\r
1831 if (EFI_ERROR (Status)) {\r
1832 return Status;\r
1833 }\r
1834 //\r
1835 // Check whether question value has been changed.\r
1836 //\r
1837 if (StrCmp (Node->Value, Node->EditValue) != 0) {\r
1838 Question->ValueChanged = TRUE;\r
1839 } else {\r
1840 Question->ValueChanged = FALSE;\r
1841 }\r
1842 }\r
1843 } else if (SetValueTo == GetSetValueWithHiiDriver) {\r
1844 //\r
1845 // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" ||\r
1846 // <ConfigHdr> + "&" + <VariableName> + "=" + "<string>"\r
1847 //\r
1848 if (IsBufferStorage) {\r
1849 Length = StrLen (Question->BlockName) + 7;\r
1850 } else {\r
1851 Length = StrLen (Question->VariableName) + 2;\r
1852 }\r
1853 if (!IsBufferStorage && IsString) {\r
1854 Length += (StrLen ((CHAR16 *) Src) * 4);\r
1855 } else {\r
1856 Length += (StorageWidth * 2);\r
1857 }\r
1858 ConfigResp = AllocateZeroPool ((StrLen (Storage->ConfigHdr) + Length + 1) * sizeof (CHAR16));\r
1859 ASSERT (ConfigResp != NULL);\r
1860\r
1861 StrCpy (ConfigResp, Storage->ConfigHdr);\r
1862 if (IsBufferStorage) {\r
1863 StrCat (ConfigResp, Question->BlockName);\r
1864 StrCat (ConfigResp, L"&VALUE=");\r
1865 } else {\r
1866 StrCat (ConfigResp, L"&");\r
1867 StrCat (ConfigResp, Question->VariableName);\r
1868 StrCat (ConfigResp, L"=");\r
1869 }\r
1870\r
1871 Value = ConfigResp + StrLen (ConfigResp);\r
1872\r
1873 if (!IsBufferStorage && IsString) {\r
1874 //\r
1875 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"\r
1876 //\r
1877 TemName = (CHAR16 *) Src;\r
1878 TemString = Value;\r
1879 for (; *TemName != L'\0'; TemName++) {\r
1880 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);\r
1881 }\r
1882 } else {\r
1883 //\r
1884 // Convert Buffer to Hex String\r
1885 //\r
1886 TemBuffer = Src + StorageWidth - 1;\r
1887 TemString = Value;\r
1888 for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {\r
1889 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);\r
1890 }\r
1891 }\r
1892\r
1893 //\r
1894 // Convert to lower char.\r
1895 //\r
1896 for (TemString = Value; *Value != L'\0'; Value++) {\r
1897 if (*Value >= L'A' && *Value <= L'Z') {\r
1898 *Value = (CHAR16) (*Value - L'A' + L'a');\r
1899 }\r
1900 }\r
1901\r
1902 //\r
1903 // Submit Question Value to Configuration Driver\r
1904 //\r
1905 Status = mHiiConfigRouting->RouteConfig (\r
1906 mHiiConfigRouting,\r
1907 ConfigResp,\r
1908 &Progress\r
1909 );\r
1910 if (EFI_ERROR (Status)) {\r
1911 FreePool (ConfigResp);\r
1912 return Status;\r
1913 }\r
1914 FreePool (ConfigResp);\r
1915 \r
1916 //\r
1917 // Sync storage, from editbuffer to buffer.\r
1918 //\r
1919 CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);\r
1920 }\r
1921\r
1922 return Status;\r
1923}\r
1924\r
1925\r
1926/**\r
1927 Perform nosubmitif check for a Form.\r
1928\r
1929 @param FormSet FormSet data structure.\r
1930 @param Form Form data structure.\r
1931 @param Question The Question to be validated.\r
1932 @param Type Validation type: NoSubmit\r
1933\r
1934 @retval EFI_SUCCESS Form validation pass.\r
1935 @retval other Form validation failed.\r
1936\r
1937**/\r
1938EFI_STATUS\r
1939ValidateQuestion (\r
1940 IN FORM_BROWSER_FORMSET *FormSet,\r
1941 IN FORM_BROWSER_FORM *Form,\r
1942 IN FORM_BROWSER_STATEMENT *Question,\r
1943 IN UINTN Type\r
1944 )\r
1945{\r
1946 EFI_STATUS Status;\r
1947 LIST_ENTRY *Link;\r
1948 LIST_ENTRY *ListHead;\r
1949 EFI_STRING PopUp;\r
1950 FORM_EXPRESSION *Expression;\r
1951\r
1952 if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {\r
1953 ListHead = &Question->NoSubmitListHead;\r
1954 } else {\r
1955 return EFI_UNSUPPORTED;\r
1956 }\r
1957\r
1958 Link = GetFirstNode (ListHead);\r
1959 while (!IsNull (ListHead, Link)) {\r
1960 Expression = FORM_EXPRESSION_FROM_LINK (Link);\r
1961\r
1962 //\r
1963 // Evaluate the expression\r
1964 //\r
1965 Status = EvaluateExpression (FormSet, Form, Expression);\r
1966 if (EFI_ERROR (Status)) {\r
1967 return Status;\r
1968 }\r
1969\r
1970 if ((Expression->Result.Type == EFI_IFR_TYPE_BOOLEAN) && Expression->Result.Value.b) {\r
1971 //\r
1972 // Condition meet, show up error message\r
1973 //\r
1974 if (Expression->Error != 0) {\r
1975 PopUp = GetToken (Expression->Error, FormSet->HiiHandle);\r
1976 if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {\r
1977 gBrowserStatus = BROWSER_NO_SUBMIT_IF;\r
1978 gErrorInfo = PopUp;\r
1979 }\r
1980 }\r
1981\r
1982 return EFI_NOT_READY;\r
1983 }\r
1984\r
1985 Link = GetNextNode (ListHead, Link);\r
1986 }\r
1987\r
1988 return EFI_SUCCESS;\r
1989}\r
1990\r
1991\r
1992/**\r
1993 Perform NoSubmit check for each Form in FormSet.\r
1994\r
1995 @param FormSet FormSet data structure.\r
1996 @param CurrentForm Current input form data structure.\r
1997\r
1998 @retval EFI_SUCCESS Form validation pass.\r
1999 @retval other Form validation failed.\r
2000\r
2001**/\r
2002EFI_STATUS\r
2003NoSubmitCheck (\r
2004 IN FORM_BROWSER_FORMSET *FormSet,\r
2005 IN FORM_BROWSER_FORM *CurrentForm\r
2006 )\r
2007{\r
2008 EFI_STATUS Status;\r
2009 LIST_ENTRY *Link;\r
2010 FORM_BROWSER_STATEMENT *Question;\r
2011 FORM_BROWSER_FORM *Form;\r
2012 LIST_ENTRY *LinkForm;\r
2013\r
2014 LinkForm = GetFirstNode (&FormSet->FormListHead);\r
2015 while (!IsNull (&FormSet->FormListHead, LinkForm)) {\r
2016 Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm);\r
2017 LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm);\r
2018\r
2019 if (CurrentForm != NULL && CurrentForm != Form) {\r
2020 continue;\r
2021 }\r
2022\r
2023 Link = GetFirstNode (&Form->StatementListHead);\r
2024 while (!IsNull (&Form->StatementListHead, Link)) {\r
2025 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
2026\r
2027 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF);\r
2028 if (EFI_ERROR (Status)) {\r
2029 return Status;\r
2030 }\r
2031\r
2032 Link = GetNextNode (&Form->StatementListHead, Link);\r
2033 }\r
2034 }\r
2035\r
2036 return EFI_SUCCESS;\r
2037}\r
2038\r
2039/**\r
2040 Fill storage's edit copy with settings requested from Configuration Driver.\r
2041\r
2042 @param FormSet FormSet data structure.\r
2043 @param Storage The storage which need to sync.\r
2044 @param ConfigRequest The config request string which used to sync storage.\r
2045 @param SyncOrRestore Sync the buffer to editbuffer or Restore the \r
2046 editbuffer to buffer\r
2047 if TRUE, copy the editbuffer to the buffer.\r
2048 if FALSE, copy the buffer to the editbuffer.\r
2049\r
2050 @retval EFI_SUCCESS The function completed successfully.\r
2051\r
2052**/\r
2053EFI_STATUS\r
2054SynchronizeStorage (\r
2055 IN FORM_BROWSER_FORMSET *FormSet,\r
2056 OUT BROWSER_STORAGE *Storage,\r
2057 IN CHAR16 *ConfigRequest,\r
2058 IN BOOLEAN SyncOrRestore\r
2059 )\r
2060{\r
2061 EFI_STATUS Status;\r
2062 EFI_STRING Progress;\r
2063 EFI_STRING Result;\r
2064 UINTN BufferSize;\r
2065 LIST_ENTRY *Link;\r
2066 NAME_VALUE_NODE *Node;\r
2067 UINT8 *Src;\r
2068 UINT8 *Dst;\r
2069\r
2070 Status = EFI_SUCCESS;\r
2071 Result = NULL;\r
2072\r
2073 if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
2074 (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {\r
2075 BufferSize = Storage->Size;\r
2076\r
2077 if (SyncOrRestore) {\r
2078 Src = Storage->EditBuffer;\r
2079 Dst = Storage->Buffer;\r
2080 } else {\r
2081 Src = Storage->Buffer;\r
2082 Dst = Storage->EditBuffer;\r
2083 }\r
2084\r
2085 if (ConfigRequest != NULL) {\r
2086 Status = mHiiConfigRouting->BlockToConfig(\r
2087 mHiiConfigRouting,\r
2088 ConfigRequest,\r
2089 Src,\r
2090 BufferSize,\r
2091 &Result,\r
2092 &Progress\r
2093 );\r
2094 if (EFI_ERROR (Status)) {\r
2095 return Status;\r
2096 }\r
2097\r
2098 Status = mHiiConfigRouting->ConfigToBlock (\r
2099 mHiiConfigRouting,\r
2100 Result,\r
2101 Dst,\r
2102 &BufferSize,\r
2103 &Progress\r
2104 );\r
2105 if (Result != NULL) {\r
2106 FreePool (Result);\r
2107 }\r
2108 } else {\r
2109 CopyMem (Dst, Src, BufferSize);\r
2110 }\r
2111 } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
2112 Link = GetFirstNode (&Storage->NameValueListHead);\r
2113 while (!IsNull (&Storage->NameValueListHead, Link)) {\r
2114 Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
2115\r
2116 if ((ConfigRequest != NULL && StrStr (ConfigRequest, Node->Name) != NULL) ||\r
2117 (ConfigRequest == NULL)) {\r
2118 if (SyncOrRestore) {\r
2119 NewStringCpy (&Node->Value, Node->EditValue);\r
2120 } else {\r
2121 NewStringCpy (&Node->EditValue, Node->Value);\r
2122 }\r
2123 }\r
2124\r
2125 Link = GetNextNode (&Storage->NameValueListHead, Link);\r
2126 }\r
2127 }\r
2128\r
2129 return Status;\r
2130}\r
2131\r
2132/**\r
2133 When discard the question value, call the callback function with Changed type\r
2134 to inform the hii driver.\r
2135\r
2136 @param FormSet FormSet data structure.\r
2137 @param Form Form data structure.\r
2138\r
2139**/\r
2140VOID\r
2141SendDiscardInfoToDriver (\r
2142 IN FORM_BROWSER_FORMSET *FormSet,\r
2143 IN FORM_BROWSER_FORM *Form\r
2144 )\r
2145{\r
2146 LIST_ENTRY *Link;\r
2147 FORM_BROWSER_STATEMENT *Question;\r
2148 EFI_IFR_TYPE_VALUE *TypeValue;\r
2149 EFI_BROWSER_ACTION_REQUEST ActionRequest;\r
2150\r
2151 Link = GetFirstNode (&Form->StatementListHead);\r
2152 while (!IsNull (&Form->StatementListHead, Link)) {\r
2153 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
2154 Link = GetNextNode (&Form->StatementListHead, Link);\r
2155\r
2156 if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
2157 continue;\r
2158 }\r
2159\r
2160 if (Question->Operand == EFI_IFR_PASSWORD_OP) {\r
2161 continue;\r
2162 }\r
2163\r
2164 if (!Question->ValueChanged) {\r
2165 continue;\r
2166 }\r
2167\r
2168 if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {\r
2169 TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;\r
2170 } else {\r
2171 TypeValue = &Question->HiiValue.Value;\r
2172 }\r
2173\r
2174 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
2175 FormSet->ConfigAccess->Callback (\r
2176 FormSet->ConfigAccess,\r
2177 EFI_BROWSER_ACTION_CHANGED,\r
2178 Question->QuestionId,\r
2179 Question->HiiValue.Type,\r
2180 TypeValue,\r
2181 &ActionRequest\r
2182 );\r
2183 }\r
2184}\r
2185\r
2186/**\r
2187 Validate the FormSet. If the formset is not validate, remove it from the list.\r
2188\r
2189 @param FormSet The input FormSet which need to validate.\r
2190\r
2191 @retval TRUE The handle is validate.\r
2192 @retval FALSE The handle is invalidate.\r
2193\r
2194**/\r
2195BOOLEAN\r
2196ValidateFormSet (\r
2197 FORM_BROWSER_FORMSET *FormSet\r
2198 )\r
2199{\r
2200 EFI_HII_HANDLE *HiiHandles;\r
2201 UINTN Index;\r
2202 BOOLEAN Find;\r
2203\r
2204 ASSERT (FormSet != NULL);\r
2205 Find = FALSE;\r
2206 //\r
2207 // Get all the Hii handles\r
2208 //\r
2209 HiiHandles = HiiGetHiiHandles (NULL);\r
2210 ASSERT (HiiHandles != NULL);\r
2211\r
2212 //\r
2213 // Search for formset of each class type\r
2214 //\r
2215 for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
2216 if (HiiHandles[Index] == FormSet->HiiHandle) {\r
2217 Find = TRUE;\r
2218 break;\r
2219 }\r
2220 }\r
2221\r
2222 if (!Find) {\r
2223 CleanBrowserStorage(FormSet);\r
2224 RemoveEntryList (&FormSet->Link);\r
2225 DestroyFormSet (FormSet);\r
2226 }\r
2227\r
2228 FreePool (HiiHandles);\r
2229\r
2230 return Find;\r
2231}\r
2232/**\r
2233 Check whether need to enable the reset flag in form level.\r
2234 Also clean all ValueChanged flag in question.\r
2235\r
2236 @param SetFlag Whether need to set the Reset Flag.\r
2237 @param Form Form data structure.\r
2238\r
2239**/\r
2240VOID\r
2241UpdateFlagForForm (\r
2242 IN BOOLEAN SetFlag,\r
2243 IN FORM_BROWSER_FORM *Form\r
2244 )\r
2245{\r
2246 LIST_ENTRY *Link;\r
2247 FORM_BROWSER_STATEMENT *Question;\r
2248 BOOLEAN FindOne;\r
2249\r
2250 FindOne = FALSE;\r
2251 Link = GetFirstNode (&Form->StatementListHead);\r
2252 while (!IsNull (&Form->StatementListHead, Link)) {\r
2253 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
2254 \r
2255 if (SetFlag && Question->ValueChanged && ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0)) {\r
2256 gResetRequired = TRUE;\r
2257 } \r
2258\r
2259 if (Question->ValueChanged) {\r
2260 Question->ValueChanged = FALSE;\r
2261 }\r
2262 \r
2263 Link = GetNextNode (&Form->StatementListHead, Link);\r
2264 }\r
2265}\r
2266\r
2267/**\r
2268 Check whether need to enable the reset flag.\r
2269 Also clean ValueChanged flag for all statements.\r
2270\r
2271 Form level or formset level, only one.\r
2272 \r
2273 @param SetFlag Whether need to set the Reset Flag.\r
2274 @param FormSet FormSet data structure.\r
2275 @param Form Form data structure.\r
2276\r
2277**/\r
2278VOID\r
2279ValueChangeResetFlagUpdate (\r
2280 IN BOOLEAN SetFlag,\r
2281 IN FORM_BROWSER_FORMSET *FormSet,\r
2282 IN FORM_BROWSER_FORM *Form \r
2283 )\r
2284{\r
2285 FORM_BROWSER_FORM *CurrentForm;\r
2286 LIST_ENTRY *Link;\r
2287\r
2288 //\r
2289 // Form != NULL means only check form level.\r
2290 //\r
2291 if (Form != NULL) {\r
2292 UpdateFlagForForm(SetFlag, Form);\r
2293 return;\r
2294 }\r
2295\r
2296 Link = GetFirstNode (&FormSet->FormListHead);\r
2297 while (!IsNull (&FormSet->FormListHead, Link)) {\r
2298 CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link);\r
2299 Link = GetNextNode (&FormSet->FormListHead, Link);\r
2300\r
2301 UpdateFlagForForm(SetFlag, CurrentForm);\r
2302 }\r
2303}\r
2304\r
2305/**\r
2306 Discard data based on the input setting scope (Form, FormSet or System).\r
2307\r
2308 @param FormSet FormSet data structure.\r
2309 @param Form Form data structure.\r
2310 @param SettingScope Setting Scope for Discard action.\r
2311\r
2312 @retval EFI_SUCCESS The function completed successfully.\r
2313 @retval EFI_UNSUPPORTED Unsupport SettingScope.\r
2314\r
2315**/\r
2316EFI_STATUS\r
2317DiscardForm (\r
2318 IN FORM_BROWSER_FORMSET *FormSet,\r
2319 IN FORM_BROWSER_FORM *Form,\r
2320 IN BROWSER_SETTING_SCOPE SettingScope\r
2321 )\r
2322{\r
2323 LIST_ENTRY *Link;\r
2324 FORMSET_STORAGE *Storage;\r
2325 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;\r
2326 FORM_BROWSER_FORMSET *LocalFormSet;\r
2327 FORM_BROWSER_FORMSET *OldFormSet;\r
2328\r
2329 //\r
2330 // Check the supported setting level.\r
2331 //\r
2332 if (SettingScope >= MaxLevel) {\r
2333 return EFI_UNSUPPORTED;\r
2334 }\r
2335\r
2336 if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) {\r
2337 ConfigInfo = NULL;\r
2338 Link = GetFirstNode (&Form->ConfigRequestHead);\r
2339 while (!IsNull (&Form->ConfigRequestHead, Link)) {\r
2340 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);\r
2341 Link = GetNextNode (&Form->ConfigRequestHead, Link);\r
2342\r
2343 if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
2344 continue;\r
2345 }\r
2346\r
2347 //\r
2348 // Skip if there is no RequestElement\r
2349 //\r
2350 if (ConfigInfo->ElementCount == 0) {\r
2351 continue;\r
2352 }\r
2353\r
2354 //\r
2355 // Prepare <ConfigResp>\r
2356 //\r
2357 SynchronizeStorage(FormSet, ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE);\r
2358\r
2359 //\r
2360 // Call callback with Changed type to inform the driver.\r
2361 //\r
2362 SendDiscardInfoToDriver (FormSet, Form);\r
2363 }\r
2364\r
2365 ValueChangeResetFlagUpdate (FALSE, NULL, Form);\r
2366 } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) {\r
2367\r
2368 //\r
2369 // Discard Buffer storage or Name/Value storage\r
2370 //\r
2371 Link = GetFirstNode (&FormSet->StorageListHead);\r
2372 while (!IsNull (&FormSet->StorageListHead, Link)) {\r
2373 Storage = FORMSET_STORAGE_FROM_LINK (Link);\r
2374 Link = GetNextNode (&FormSet->StorageListHead, Link);\r
2375\r
2376 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
2377 continue;\r
2378 }\r
2379\r
2380 //\r
2381 // Skip if there is no RequestElement\r
2382 //\r
2383 if (Storage->ElementCount == 0) {\r
2384 continue;\r
2385 }\r
2386\r
2387 SynchronizeStorage(FormSet, Storage->BrowserStorage, Storage->ConfigRequest, FALSE);\r
2388 }\r
2389\r
2390 Link = GetFirstNode (&FormSet->FormListHead);\r
2391 while (!IsNull (&FormSet->FormListHead, Link)) {\r
2392 Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
2393 Link = GetNextNode (&FormSet->FormListHead, Link);\r
2394 \r
2395 //\r
2396 // Call callback with Changed type to inform the driver.\r
2397 //\r
2398 SendDiscardInfoToDriver (FormSet, Form);\r
2399 }\r
2400\r
2401 ValueChangeResetFlagUpdate(FALSE, FormSet, NULL);\r
2402 } else if (SettingScope == SystemLevel) {\r
2403 //\r
2404 // System Level Discard.\r
2405 //\r
2406 OldFormSet = mSystemLevelFormSet;\r
2407\r
2408 //\r
2409 // Discard changed value for each FormSet in the maintain list.\r
2410 //\r
2411 Link = GetFirstNode (&gBrowserFormSetList);\r
2412 while (!IsNull (&gBrowserFormSetList, Link)) {\r
2413 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
2414 Link = GetNextNode (&gBrowserFormSetList, Link);\r
2415 if (!ValidateFormSet(LocalFormSet)) {\r
2416 continue;\r
2417 }\r
2418\r
2419 mSystemLevelFormSet = LocalFormSet;\r
2420\r
2421 DiscardForm (LocalFormSet, NULL, FormSetLevel);\r
2422 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {\r
2423 //\r
2424 // Remove maintain backup list after discard except for the current using FormSet.\r
2425 //\r
2426 CleanBrowserStorage(LocalFormSet);\r
2427 RemoveEntryList (&LocalFormSet->Link);\r
2428 DestroyFormSet (LocalFormSet);\r
2429 }\r
2430 }\r
2431\r
2432 mSystemLevelFormSet = OldFormSet;\r
2433 }\r
2434\r
2435 return EFI_SUCCESS; \r
2436}\r
2437\r
2438/**\r
2439 Submit data based on the input Setting level (Form, FormSet or System).\r
2440\r
2441 @param FormSet FormSet data structure.\r
2442 @param Form Form data structure.\r
2443 @param SettingScope Setting Scope for Submit action.\r
2444\r
2445 @retval EFI_SUCCESS The function completed successfully.\r
2446 @retval EFI_UNSUPPORTED Unsupport SettingScope.\r
2447\r
2448**/\r
2449EFI_STATUS\r
2450SubmitForm (\r
2451 IN FORM_BROWSER_FORMSET *FormSet,\r
2452 IN FORM_BROWSER_FORM *Form,\r
2453 IN BROWSER_SETTING_SCOPE SettingScope\r
2454 )\r
2455{\r
2456 EFI_STATUS Status;\r
2457 LIST_ENTRY *Link;\r
2458 EFI_STRING ConfigResp;\r
2459 EFI_STRING Progress;\r
2460 BROWSER_STORAGE *Storage;\r
2461 FORMSET_STORAGE *FormSetStorage;\r
2462 FORM_BROWSER_FORMSET *LocalFormSet;\r
2463 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;\r
2464\r
2465 //\r
2466 // Check the supported setting level.\r
2467 //\r
2468 if (SettingScope >= MaxLevel) {\r
2469 return EFI_UNSUPPORTED;\r
2470 }\r
2471\r
2472 //\r
2473 // Validate the Form by NoSubmit check\r
2474 //\r
2475 Status = EFI_SUCCESS;\r
2476 if (SettingScope == FormLevel) {\r
2477 Status = NoSubmitCheck (FormSet, Form);\r
2478 } else if (SettingScope == FormSetLevel) {\r
2479 Status = NoSubmitCheck (FormSet, NULL);\r
2480 }\r
2481 if (EFI_ERROR (Status)) {\r
2482 return Status;\r
2483 }\r
2484\r
2485 if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) {\r
2486 ConfigInfo = NULL;\r
2487 Link = GetFirstNode (&Form->ConfigRequestHead);\r
2488 while (!IsNull (&Form->ConfigRequestHead, Link)) {\r
2489 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);\r
2490 Link = GetNextNode (&Form->ConfigRequestHead, Link);\r
2491\r
2492 Storage = ConfigInfo->Storage;\r
2493 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
2494 continue;\r
2495 }\r
2496\r
2497 //\r
2498 // Skip if there is no RequestElement\r
2499 //\r
2500 if (ConfigInfo->ElementCount == 0) {\r
2501 continue;\r
2502 }\r
2503\r
2504 //\r
2505 // 1. Prepare <ConfigResp>\r
2506 //\r
2507 Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE);\r
2508 if (EFI_ERROR (Status)) {\r
2509 return Status;\r
2510 }\r
2511\r
2512 //\r
2513 // 2. Set value to hii config routine protocol.\r
2514 //\r
2515 Status = mHiiConfigRouting->RouteConfig (\r
2516 mHiiConfigRouting,\r
2517 ConfigResp,\r
2518 &Progress\r
2519 );\r
2520 if (EFI_ERROR (Status)) {\r
2521 FreePool (ConfigResp);\r
2522 return Status;\r
2523 }\r
2524\r
2525 FreePool (ConfigResp);\r
2526 //\r
2527 // 3. Config success, update storage shadow Buffer, only update the data belong to this form.\r
2528 //\r
2529 SynchronizeStorage (FormSet, ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE);\r
2530 }\r
2531\r
2532 //\r
2533 // 4. Update the NV flag.\r
2534 // \r
2535 ValueChangeResetFlagUpdate(TRUE, NULL, Form);\r
2536 } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) {\r
2537 //\r
2538 // Submit Buffer storage or Name/Value storage\r
2539 //\r
2540 Link = GetFirstNode (&FormSet->StorageListHead);\r
2541 while (!IsNull (&FormSet->StorageListHead, Link)) {\r
2542 FormSetStorage = (FORMSET_STORAGE_FROM_LINK (Link));\r
2543 Storage = FormSetStorage->BrowserStorage;\r
2544 Link = GetNextNode (&FormSet->StorageListHead, Link);\r
2545\r
2546 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
2547 continue;\r
2548 }\r
2549\r
2550 //\r
2551 // Skip if there is no RequestElement\r
2552 //\r
2553 if (FormSetStorage->ElementCount == 0) {\r
2554 continue;\r
2555 }\r
2556\r
2557 //\r
2558 // 1. Prepare <ConfigResp>\r
2559 //\r
2560 Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE);\r
2561 if (EFI_ERROR (Status)) {\r
2562 return Status;\r
2563 }\r
2564\r
2565 //\r
2566 // 2. Send <ConfigResp> to Routine config Protocol.\r
2567 //\r
2568 Status = mHiiConfigRouting->RouteConfig (\r
2569 mHiiConfigRouting,\r
2570 ConfigResp,\r
2571 &Progress\r
2572 );\r
2573 if (EFI_ERROR (Status)) {\r
2574 FreePool (ConfigResp);\r
2575 return Status;\r
2576 }\r
2577\r
2578 FreePool (ConfigResp);\r
2579 //\r
2580 // 3. Config success, update storage shadow Buffer\r
2581 //\r
2582 SynchronizeStorage (FormSet, Storage, FormSetStorage->ConfigRequest, TRUE);\r
2583 }\r
2584\r
2585 //\r
2586 // 4. Update the NV flag.\r
2587 // \r
2588 ValueChangeResetFlagUpdate(TRUE, FormSet, NULL);\r
2589 } else if (SettingScope == SystemLevel) {\r
2590 //\r
2591 // System Level Save.\r
2592 //\r
2593\r
2594 //\r
2595 // Save changed value for each FormSet in the maintain list.\r
2596 //\r
2597 Link = GetFirstNode (&gBrowserFormSetList);\r
2598 while (!IsNull (&gBrowserFormSetList, Link)) {\r
2599 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
2600 Link = GetNextNode (&gBrowserFormSetList, Link);\r
2601 if (!ValidateFormSet(LocalFormSet)) {\r
2602 continue;\r
2603 }\r
2604 SubmitForm (LocalFormSet, NULL, FormSetLevel);\r
2605 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {\r
2606 //\r
2607 // Remove maintain backup list after save except for the current using FormSet.\r
2608 //\r
2609 CleanBrowserStorage(LocalFormSet);\r
2610 RemoveEntryList (&LocalFormSet->Link);\r
2611 DestroyFormSet (LocalFormSet);\r
2612 }\r
2613 }\r
2614 }\r
2615\r
2616 return EFI_SUCCESS;\r
2617}\r
2618\r
2619/**\r
2620 Get Question default value from AltCfg string.\r
2621\r
2622 @param FormSet The form set.\r
2623 @param Question The question.\r
2624 @param DefaultId The default Id.\r
2625\r
2626 @retval EFI_SUCCESS Question is reset to default value.\r
2627\r
2628**/\r
2629EFI_STATUS\r
2630GetDefaultValueFromAltCfg (\r
2631 IN FORM_BROWSER_FORMSET *FormSet,\r
2632 IN OUT FORM_BROWSER_STATEMENT *Question,\r
2633 IN UINT16 DefaultId\r
2634 )\r
2635{\r
2636 BOOLEAN IsBufferStorage;\r
2637 BOOLEAN IsString; \r
2638 UINTN Length;\r
2639 BROWSER_STORAGE *Storage;\r
2640 CHAR16 *ConfigRequest;\r
2641 CHAR16 *Progress;\r
2642 CHAR16 *Result;\r
2643 CHAR16 *ConfigResp;\r
2644 CHAR16 *Value;\r
2645 CHAR16 *StringPtr;\r
2646 UINTN LengthStr;\r
2647 UINT8 *Dst;\r
2648 CHAR16 TemStr[5];\r
2649 UINTN Index;\r
2650 UINT8 DigitUint8;\r
2651 EFI_STATUS Status;\r
2652\r
2653 Status = EFI_NOT_FOUND;\r
2654 Length = 0;\r
2655 Dst = NULL;\r
2656 ConfigRequest = NULL;\r
2657 Result = NULL;\r
2658 ConfigResp = NULL;\r
2659 Value = NULL;\r
2660 Storage = Question->Storage;\r
2661\r
2662 if ((Storage == NULL) || (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {\r
2663 return Status;\r
2664 }\r
2665\r
2666 //\r
2667 // Question Value is provided by Buffer Storage or NameValue Storage\r
2668 //\r
2669 if (Question->BufferValue != NULL) {\r
2670 //\r
2671 // This Question is password or orderedlist\r
2672 //\r
2673 Dst = Question->BufferValue;\r
2674 } else {\r
2675 //\r
2676 // Other type of Questions\r
2677 //\r
2678 Dst = (UINT8 *) &Question->HiiValue.Value;\r
2679 }\r
2680\r
2681 if (Storage->Type == EFI_HII_VARSTORE_BUFFER || Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
2682 IsBufferStorage = TRUE;\r
2683 } else {\r
2684 IsBufferStorage = FALSE;\r
2685 }\r
2686 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);\r
2687\r
2688 //\r
2689 // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||\r
2690 // <ConfigHdr> + "&" + <VariableName>\r
2691 //\r
2692 if (IsBufferStorage) {\r
2693 Length = StrLen (Storage->ConfigHdr);\r
2694 Length += StrLen (Question->BlockName);\r
2695 } else {\r
2696 Length = StrLen (Storage->ConfigHdr);\r
2697 Length += StrLen (Question->VariableName) + 1;\r
2698 }\r
2699 ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));\r
2700 ASSERT (ConfigRequest != NULL);\r
2701\r
2702 StrCpy (ConfigRequest, Storage->ConfigHdr);\r
2703 if (IsBufferStorage) {\r
2704 StrCat (ConfigRequest, Question->BlockName);\r
2705 } else {\r
2706 StrCat (ConfigRequest, L"&");\r
2707 StrCat (ConfigRequest, Question->VariableName);\r
2708 }\r
2709\r
2710 Status = mHiiConfigRouting->ExtractConfig (\r
2711 mHiiConfigRouting,\r
2712 ConfigRequest,\r
2713 &Progress,\r
2714 &Result\r
2715 );\r
2716 if (EFI_ERROR (Status)) {\r
2717 goto Done;\r
2718 }\r
2719\r
2720 //\r
2721 // Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)\r
2722 // Get the default configuration string according to the default ID.\r
2723 //\r
2724 Status = mHiiConfigRouting->GetAltConfig (\r
2725 mHiiConfigRouting,\r
2726 Result,\r
2727 &Storage->Guid,\r
2728 Storage->Name,\r
2729 NULL,\r
2730 &DefaultId, // it can be NULL to get the current setting.\r
2731 &ConfigResp\r
2732 );\r
2733 \r
2734 //\r
2735 // The required setting can't be found. So, it is not required to be validated and set.\r
2736 //\r
2737 if (EFI_ERROR (Status)) {\r
2738 goto Done;\r
2739 }\r
2740\r
2741 if (ConfigResp == NULL) {\r
2742 Status = EFI_NOT_FOUND;\r
2743 goto Done;\r
2744 }\r
2745\r
2746 //\r
2747 // Skip <ConfigRequest>\r
2748 //\r
2749 if (IsBufferStorage) {\r
2750 Value = StrStr (ConfigResp, L"&VALUE");\r
2751 ASSERT (Value != NULL);\r
2752 //\r
2753 // Skip "&VALUE"\r
2754 //\r
2755 Value = Value + 6;\r
2756 } else {\r
2757 Value = StrStr (ConfigResp, Question->VariableName);\r
2758 ASSERT (Value != NULL);\r
2759\r
2760 Value = Value + StrLen (Question->VariableName);\r
2761 }\r
2762 if (*Value != '=') {\r
2763 Status = EFI_NOT_FOUND;\r
2764 goto Done;\r
2765 }\r
2766 //\r
2767 // Skip '=', point to value\r
2768 //\r
2769 Value = Value + 1;\r
2770\r
2771 //\r
2772 // Suppress <AltResp> if any\r
2773 //\r
2774 StringPtr = Value;\r
2775 while (*StringPtr != L'\0' && *StringPtr != L'&') {\r
2776 StringPtr++;\r
2777 }\r
2778 *StringPtr = L'\0';\r
2779\r
2780 LengthStr = StrLen (Value);\r
2781 if (!IsBufferStorage && IsString) {\r
2782 StringPtr = (CHAR16 *) Dst;\r
2783 ZeroMem (TemStr, sizeof (TemStr));\r
2784 for (Index = 0; Index < LengthStr; Index += 4) {\r
2785 StrnCpy (TemStr, Value + Index, 4);\r
2786 StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);\r
2787 }\r
2788 //\r
2789 // Add tailing L'\0' character\r
2790 //\r
2791 StringPtr[Index/4] = L'\0';\r
2792 } else {\r
2793 ZeroMem (TemStr, sizeof (TemStr));\r
2794 for (Index = 0; Index < LengthStr; Index ++) {\r
2795 TemStr[0] = Value[LengthStr - Index - 1];\r
2796 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
2797 if ((Index & 1) == 0) {\r
2798 Dst [Index/2] = DigitUint8;\r
2799 } else {\r
2800 Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);\r
2801 }\r
2802 }\r
2803 }\r
2804\r
2805Done:\r
2806 if (ConfigRequest != NULL){\r
2807 FreePool (ConfigRequest);\r
2808 }\r
2809\r
2810 if (ConfigResp != NULL) {\r
2811 FreePool (ConfigResp);\r
2812 }\r
2813 \r
2814 if (Result != NULL) {\r
2815 FreePool (Result);\r
2816 }\r
2817\r
2818 return Status;\r
2819}\r
2820\r
2821/**\r
2822 Get default Id value used for browser.\r
2823\r
2824 @param DefaultId The default id value used by hii.\r
2825\r
2826 @retval Browser used default value.\r
2827\r
2828**/\r
2829INTN\r
2830GetDefaultIdForCallBack (\r
2831 UINTN DefaultId\r
2832 )\r
2833{ \r
2834 if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {\r
2835 return EFI_BROWSER_ACTION_DEFAULT_STANDARD;\r
2836 } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {\r
2837 return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;\r
2838 } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {\r
2839 return EFI_BROWSER_ACTION_DEFAULT_SAFE;\r
2840 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) {\r
2841 return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;\r
2842 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) {\r
2843 return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;\r
2844 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) {\r
2845 return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;\r
2846 } else {\r
2847 return -1;\r
2848 }\r
2849}\r
2850\r
2851\r
2852\r
2853/**\r
2854 Return data element in an Array by its Index.\r
2855\r
2856 @param Array The data array.\r
2857 @param Type Type of the data in this array.\r
2858 @param Index Zero based index for data in this array.\r
2859\r
2860 @retval Value The data to be returned\r
2861\r
2862**/\r
2863UINT64\r
2864GetArrayData (\r
2865 IN VOID *Array,\r
2866 IN UINT8 Type,\r
2867 IN UINTN Index\r
2868 )\r
2869{\r
2870 UINT64 Data;\r
2871\r
2872 ASSERT (Array != NULL);\r
2873\r
2874 Data = 0;\r
2875 switch (Type) {\r
2876 case EFI_IFR_TYPE_NUM_SIZE_8:\r
2877 Data = (UINT64) *(((UINT8 *) Array) + Index);\r
2878 break;\r
2879\r
2880 case EFI_IFR_TYPE_NUM_SIZE_16:\r
2881 Data = (UINT64) *(((UINT16 *) Array) + Index);\r
2882 break;\r
2883\r
2884 case EFI_IFR_TYPE_NUM_SIZE_32:\r
2885 Data = (UINT64) *(((UINT32 *) Array) + Index);\r
2886 break;\r
2887\r
2888 case EFI_IFR_TYPE_NUM_SIZE_64:\r
2889 Data = (UINT64) *(((UINT64 *) Array) + Index);\r
2890 break;\r
2891\r
2892 default:\r
2893 break;\r
2894 }\r
2895\r
2896 return Data;\r
2897}\r
2898\r
2899\r
2900/**\r
2901 Set value of a data element in an Array by its Index.\r
2902\r
2903 @param Array The data array.\r
2904 @param Type Type of the data in this array.\r
2905 @param Index Zero based index for data in this array.\r
2906 @param Value The value to be set.\r
2907\r
2908**/\r
2909VOID\r
2910SetArrayData (\r
2911 IN VOID *Array,\r
2912 IN UINT8 Type,\r
2913 IN UINTN Index,\r
2914 IN UINT64 Value\r
2915 )\r
2916{\r
2917\r
2918 ASSERT (Array != NULL);\r
2919\r
2920 switch (Type) {\r
2921 case EFI_IFR_TYPE_NUM_SIZE_8:\r
2922 *(((UINT8 *) Array) + Index) = (UINT8) Value;\r
2923 break;\r
2924\r
2925 case EFI_IFR_TYPE_NUM_SIZE_16:\r
2926 *(((UINT16 *) Array) + Index) = (UINT16) Value;\r
2927 break;\r
2928\r
2929 case EFI_IFR_TYPE_NUM_SIZE_32:\r
2930 *(((UINT32 *) Array) + Index) = (UINT32) Value;\r
2931 break;\r
2932\r
2933 case EFI_IFR_TYPE_NUM_SIZE_64:\r
2934 *(((UINT64 *) Array) + Index) = (UINT64) Value;\r
2935 break;\r
2936\r
2937 default:\r
2938 break;\r
2939 }\r
2940}\r
2941\r
2942/**\r
2943 Search an Option of a Question by its value.\r
2944\r
2945 @param Question The Question\r
2946 @param OptionValue Value for Option to be searched.\r
2947\r
2948 @retval Pointer Pointer to the found Option.\r
2949 @retval NULL Option not found.\r
2950\r
2951**/\r
2952QUESTION_OPTION *\r
2953ValueToOption (\r
2954 IN FORM_BROWSER_STATEMENT *Question,\r
2955 IN EFI_HII_VALUE *OptionValue\r
2956 )\r
2957{\r
2958 LIST_ENTRY *Link;\r
2959 QUESTION_OPTION *Option;\r
2960 INTN Result;\r
2961\r
2962 Link = GetFirstNode (&Question->OptionListHead);\r
2963 while (!IsNull (&Question->OptionListHead, Link)) {\r
2964 Option = QUESTION_OPTION_FROM_LINK (Link);\r
2965\r
2966 if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {\r
2967 //\r
2968 // Check the suppressif condition, only a valid option can be return.\r
2969 //\r
2970 if ((Option->SuppressExpression == NULL) ||\r
2971 ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) {\r
2972 return Option;\r
2973 }\r
2974 }\r
2975\r
2976 Link = GetNextNode (&Question->OptionListHead, Link);\r
2977 }\r
2978\r
2979 return NULL;\r
2980}\r
2981\r
2982\r
2983/**\r
2984 Reset Question to its default value.\r
2985\r
2986 @param FormSet The form set.\r
2987 @param Form The form.\r
2988 @param Question The question.\r
2989 @param DefaultId The Class of the default.\r
2990\r
2991 @retval EFI_SUCCESS Question is reset to default value.\r
2992\r
2993**/\r
2994EFI_STATUS\r
2995GetQuestionDefault (\r
2996 IN FORM_BROWSER_FORMSET *FormSet,\r
2997 IN FORM_BROWSER_FORM *Form,\r
2998 IN FORM_BROWSER_STATEMENT *Question,\r
2999 IN UINT16 DefaultId\r
3000 )\r
3001{\r
3002 EFI_STATUS Status;\r
3003 LIST_ENTRY *Link;\r
3004 QUESTION_DEFAULT *Default;\r
3005 QUESTION_OPTION *Option;\r
3006 EFI_HII_VALUE *HiiValue;\r
3007 UINT8 Index;\r
3008 EFI_STRING StrValue;\r
3009 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
3010 EFI_BROWSER_ACTION_REQUEST ActionRequest;\r
3011 INTN Action;\r
3012\r
3013 Status = EFI_NOT_FOUND;\r
3014 StrValue = NULL;\r
3015\r
3016 //\r
3017 // Statement don't have storage, skip them\r
3018 //\r
3019 if (Question->QuestionId == 0) {\r
3020 return Status;\r
3021 }\r
3022\r
3023 //\r
3024 // There are Five ways to specify default value for a Question:\r
3025 // 1, use call back function (highest priority)\r
3026 // 2, use ExtractConfig function\r
3027 // 3, use nested EFI_IFR_DEFAULT \r
3028 // 4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)\r
3029 // 5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)\r
3030 //\r
3031 HiiValue = &Question->HiiValue;\r
3032\r
3033 //\r
3034 // Get Question defaut value from call back function.\r
3035 //\r
3036 ConfigAccess = FormSet->ConfigAccess;\r
3037 Action = GetDefaultIdForCallBack (DefaultId);\r
3038 if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {\r
3039 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
3040 Status = ConfigAccess->Callback (\r
3041 ConfigAccess,\r
3042 Action,\r
3043 Question->QuestionId,\r
3044 HiiValue->Type,\r
3045 &HiiValue->Value,\r
3046 &ActionRequest\r
3047 );\r
3048 if (!EFI_ERROR (Status)) {\r
3049 return Status;\r
3050 }\r
3051 }\r
3052\r
3053 //\r
3054 // Get default value from altcfg string.\r
3055 //\r
3056 if (ConfigAccess != NULL) { \r
3057 Status = GetDefaultValueFromAltCfg(FormSet, Question, DefaultId);\r
3058 if (!EFI_ERROR (Status)) {\r
3059 return Status;\r
3060 }\r
3061 }\r
3062\r
3063 //\r
3064 // EFI_IFR_DEFAULT has highest priority\r
3065 //\r
3066 if (!IsListEmpty (&Question->DefaultListHead)) {\r
3067 Link = GetFirstNode (&Question->DefaultListHead);\r
3068 while (!IsNull (&Question->DefaultListHead, Link)) {\r
3069 Default = QUESTION_DEFAULT_FROM_LINK (Link);\r
3070\r
3071 if (Default->DefaultId == DefaultId) {\r
3072 if (Default->ValueExpression != NULL) {\r
3073 //\r
3074 // Default is provided by an Expression, evaluate it\r
3075 //\r
3076 Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);\r
3077 if (EFI_ERROR (Status)) {\r
3078 return Status;\r
3079 }\r
3080\r
3081 if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {\r
3082 ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && Question->BufferValue != NULL);\r
3083 if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {\r
3084 CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);\r
3085 Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;\r
3086 } else {\r
3087 CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);\r
3088 Question->HiiValue.BufferLen = Question->StorageWidth;\r
3089 }\r
3090 FreePool (Default->ValueExpression->Result.Buffer);\r
3091 }\r
3092 HiiValue->Type = Default->ValueExpression->Result.Type;\r
3093 CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE)); \r
3094 } else {\r
3095 //\r
3096 // Default value is embedded in EFI_IFR_DEFAULT\r
3097 //\r
3098 CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));\r
3099 }\r
3100\r
3101 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
3102 StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);\r
3103 if (StrValue == NULL) {\r
3104 return EFI_NOT_FOUND;\r
3105 }\r
3106 if (Question->StorageWidth > StrSize (StrValue)) {\r
3107 CopyMem (Question->BufferValue, StrValue, StrSize (StrValue));\r
3108 } else {\r
3109 CopyMem (Question->BufferValue, StrValue, Question->StorageWidth);\r
3110 }\r
3111 }\r
3112\r
3113 return EFI_SUCCESS;\r
3114 }\r
3115\r
3116 Link = GetNextNode (&Question->DefaultListHead, Link);\r
3117 }\r
3118 }\r
3119\r
3120 //\r
3121 // EFI_ONE_OF_OPTION\r
3122 //\r
3123 if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {\r
3124 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {\r
3125 //\r
3126 // OneOfOption could only provide Standard and Manufacturing default\r
3127 //\r
3128 Link = GetFirstNode (&Question->OptionListHead);\r
3129 while (!IsNull (&Question->OptionListHead, Link)) {\r
3130 Option = QUESTION_OPTION_FROM_LINK (Link);\r
3131 Link = GetNextNode (&Question->OptionListHead, Link);\r
3132\r
3133 if ((Option->SuppressExpression != NULL) &&\r
3134 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {\r
3135 continue;\r
3136 }\r
3137\r
3138 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||\r
3139 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))\r
3140 ) {\r
3141 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));\r
3142\r
3143 return EFI_SUCCESS;\r
3144 }\r
3145 }\r
3146 }\r
3147 }\r
3148\r
3149 //\r
3150 // EFI_IFR_CHECKBOX - lowest priority\r
3151 //\r
3152 if (Question->Operand == EFI_IFR_CHECKBOX_OP) {\r
3153 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {\r
3154 //\r
3155 // Checkbox could only provide Standard and Manufacturing default\r
3156 //\r
3157 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||\r
3158 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))\r
3159 ) {\r
3160 HiiValue->Value.b = TRUE;\r
3161 } else {\r
3162 HiiValue->Value.b = FALSE;\r
3163 }\r
3164\r
3165 return EFI_SUCCESS;\r
3166 }\r
3167 }\r
3168\r
3169 //\r
3170 // For Questions without default\r
3171 //\r
3172 Status = EFI_NOT_FOUND;\r
3173 switch (Question->Operand) {\r
3174 case EFI_IFR_NUMERIC_OP:\r
3175 //\r
3176 // Take minimum value as numeric default value\r
3177 //\r
3178 if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {\r
3179 HiiValue->Value.u64 = Question->Minimum;\r
3180 Status = EFI_SUCCESS;\r
3181 }\r
3182 break;\r
3183\r
3184 case EFI_IFR_ONE_OF_OP:\r
3185 //\r
3186 // Take first oneof option as oneof's default value\r
3187 //\r
3188 if (ValueToOption (Question, HiiValue) == NULL) {\r
3189 Link = GetFirstNode (&Question->OptionListHead);\r
3190 while (!IsNull (&Question->OptionListHead, Link)) {\r
3191 Option = QUESTION_OPTION_FROM_LINK (Link);\r
3192 Link = GetNextNode (&Question->OptionListHead, Link);\r
3193\r
3194 if ((Option->SuppressExpression != NULL) &&\r
3195 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {\r
3196 continue;\r
3197 }\r
3198\r
3199 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));\r
3200 Status = EFI_SUCCESS;\r
3201 break;\r
3202 }\r
3203 }\r
3204 break;\r
3205\r
3206 case EFI_IFR_ORDERED_LIST_OP:\r
3207 //\r
3208 // Take option sequence in IFR as ordered list's default value\r
3209 //\r
3210 Index = 0;\r
3211 Link = GetFirstNode (&Question->OptionListHead);\r
3212 while (!IsNull (&Question->OptionListHead, Link)) {\r
3213 Status = EFI_SUCCESS;\r
3214 Option = QUESTION_OPTION_FROM_LINK (Link);\r
3215 Link = GetNextNode (&Question->OptionListHead, Link);\r
3216\r
3217 if ((Option->SuppressExpression != NULL) &&\r
3218 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {\r
3219 continue;\r
3220 }\r
3221\r
3222 SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);\r
3223\r
3224 Index++;\r
3225 if (Index >= Question->MaxContainers) {\r
3226 break;\r
3227 }\r
3228 }\r
3229 break;\r
3230\r
3231 default:\r
3232 break;\r
3233 }\r
3234\r
3235 return Status;\r
3236}\r
3237\r
3238\r
3239/**\r
3240 Reset Questions to their initial value or default value in a Form, Formset or System.\r
3241\r
3242 GetDefaultValueScope parameter decides which questions will reset \r
3243 to its default value.\r
3244\r
3245 @param FormSet FormSet data structure.\r
3246 @param Form Form data structure.\r
3247 @param DefaultId The Class of the default.\r
3248 @param SettingScope Setting Scope for Default action.\r
3249 @param GetDefaultValueScope Get default value scope.\r
3250 @param Storage Get default value only for this storage.\r
3251 @param RetrieveValueFirst Whether call the retrieve call back to\r
3252 get the initial value before get default\r
3253 value.\r
3254\r
3255 @retval EFI_SUCCESS The function completed successfully.\r
3256 @retval EFI_UNSUPPORTED Unsupport SettingScope.\r
3257\r
3258**/\r
3259EFI_STATUS\r
3260ExtractDefault (\r
3261 IN FORM_BROWSER_FORMSET *FormSet,\r
3262 IN FORM_BROWSER_FORM *Form,\r
3263 IN UINT16 DefaultId,\r
3264 IN BROWSER_SETTING_SCOPE SettingScope,\r
3265 IN BROWSER_GET_DEFAULT_VALUE GetDefaultValueScope,\r
3266 IN BROWSER_STORAGE *Storage OPTIONAL,\r
3267 IN BOOLEAN RetrieveValueFirst\r
3268 )\r
3269{\r
3270 EFI_STATUS Status;\r
3271 LIST_ENTRY *FormLink;\r
3272 LIST_ENTRY *Link;\r
3273 FORM_BROWSER_STATEMENT *Question;\r
3274 FORM_BROWSER_FORMSET *LocalFormSet;\r
3275 FORM_BROWSER_FORMSET *OldFormSet;\r
3276\r
3277 Status = EFI_SUCCESS;\r
3278\r
3279 //\r
3280 // Check the supported setting level.\r
3281 //\r
3282 if (SettingScope >= MaxLevel || GetDefaultValueScope >= GetDefaultForMax) {\r
3283 return EFI_UNSUPPORTED;\r
3284 }\r
3285\r
3286 if (GetDefaultValueScope == GetDefaultForStorage && Storage == NULL) {\r
3287 return EFI_UNSUPPORTED;\r
3288 }\r
3289 \r
3290 if (SettingScope == FormLevel) {\r
3291 //\r
3292 // Extract Form default\r
3293 //\r
3294 Link = GetFirstNode (&Form->StatementListHead);\r
3295 while (!IsNull (&Form->StatementListHead, Link)) {\r
3296 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
3297 Link = GetNextNode (&Form->StatementListHead, Link);\r
3298\r
3299 //\r
3300 // If get default value only for this storage, check the storage first.\r
3301 //\r
3302 if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) {\r
3303 continue;\r
3304 }\r
3305\r
3306 //\r
3307 // If get default value only for no storage question, just skip the question which has storage.\r
3308 //\r
3309 if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) {\r
3310 continue;\r
3311 }\r
3312\r
3313 //\r
3314 // If Question is disabled, don't reset it to default\r
3315 //\r
3316 if (Question->Expression != NULL) {\r
3317 if (EvaluateExpressionList(Question->Expression, TRUE, FormSet, Form) == ExpressDisable) {\r
3318 continue;\r
3319 }\r
3320 }\r
3321\r
3322 if (RetrieveValueFirst) {\r
3323 //\r
3324 // Call the Retrieve call back to get the initial question value.\r
3325 //\r
3326 Status = ProcessRetrieveForQuestion(FormSet->ConfigAccess, Question);\r
3327 }\r
3328\r
3329 //\r
3330 // If not request to get the initial value or get initial value fail, then get default value.\r
3331 //\r
3332 if (!RetrieveValueFirst || EFI_ERROR (Status)) {\r
3333 Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);\r
3334 if (EFI_ERROR (Status)) {\r
3335 continue;\r
3336 }\r
3337 }\r
3338\r
3339 //\r
3340 // Synchronize Buffer storage's Edit buffer\r
3341 //\r
3342 if ((Question->Storage != NULL) &&\r
3343 (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {\r
3344 SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);\r
3345 }\r
3346 }\r
3347 } else if (SettingScope == FormSetLevel) {\r
3348 FormLink = GetFirstNode (&FormSet->FormListHead);\r
3349 while (!IsNull (&FormSet->FormListHead, FormLink)) {\r
3350 Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);\r
3351 ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst);\r
3352 FormLink = GetNextNode (&FormSet->FormListHead, FormLink);\r
3353 }\r
3354 } else if (SettingScope == SystemLevel) {\r
3355 //\r
3356 // Preload all Hii formset.\r
3357 //\r
3358 LoadAllHiiFormset();\r
3359\r
3360 OldFormSet = mSystemLevelFormSet;\r
3361\r
3362 //\r
3363 // Set Default Value for each FormSet in the maintain list.\r
3364 //\r
3365 Link = GetFirstNode (&gBrowserFormSetList);\r
3366 while (!IsNull (&gBrowserFormSetList, Link)) {\r
3367 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
3368 Link = GetNextNode (&gBrowserFormSetList, Link);\r
3369 if (!ValidateFormSet(LocalFormSet)) {\r
3370 continue;\r
3371 }\r
3372\r
3373 mSystemLevelFormSet = LocalFormSet;\r
3374\r
3375 ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst);\r
3376 }\r
3377\r
3378 mSystemLevelFormSet = OldFormSet;\r
3379 }\r
3380\r
3381 return EFI_SUCCESS;\r
3382}\r
3383\r
3384\r
3385/**\r
3386 Validate whether this question's value has changed.\r
3387\r
3388 @param FormSet FormSet data structure.\r
3389 @param Form Form data structure.\r
3390 @param Question Question to be initialized.\r
3391 @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.\r
3392\r
3393 @retval TRUE Question's value has changed.\r
3394 @retval FALSE Question's value has not changed\r
3395\r
3396**/\r
3397BOOLEAN\r
3398IsQuestionValueChanged (\r
3399 IN FORM_BROWSER_FORMSET *FormSet,\r
3400 IN FORM_BROWSER_FORM *Form,\r
3401 IN OUT FORM_BROWSER_STATEMENT *Question,\r
3402 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom\r
3403 )\r
3404{\r
3405 EFI_HII_VALUE BackUpValue;\r
3406 CHAR8 *BackUpBuffer;\r
3407 EFI_STATUS Status;\r
3408 BOOLEAN ValueChanged;\r
3409 UINTN BufferWidth;\r
3410\r
3411 //\r
3412 // For quetion without storage, always mark it as data not changed.\r
3413 //\r
3414 if (Question->Storage == NULL && Question->Operand != EFI_IFR_TIME_OP && Question->Operand != EFI_IFR_DATE_OP) {\r
3415 return FALSE;\r
3416 }\r
3417\r
3418 BackUpBuffer = NULL;\r
3419 ValueChanged = FALSE;\r
3420\r
3421 switch (Question->Operand) {\r
3422 case EFI_IFR_ORDERED_LIST_OP:\r
3423 BufferWidth = Question->StorageWidth;\r
3424 BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);\r
3425 ASSERT (BackUpBuffer != NULL);\r
3426 break;\r
3427\r
3428 case EFI_IFR_STRING_OP:\r
3429 case EFI_IFR_PASSWORD_OP:\r
3430 BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16);\r
3431 BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);\r
3432 ASSERT (BackUpBuffer != NULL);\r
3433 break;\r
3434\r
3435 default:\r
3436 BufferWidth = 0;\r
3437 break;\r
3438 }\r
3439 CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));\r
3440\r
3441 Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom);\r
3442 ASSERT_EFI_ERROR(Status);\r
3443\r
3444 if (CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||\r
3445 CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0) {\r
3446 ValueChanged = TRUE;\r
3447 }\r
3448\r
3449 CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE));\r
3450 CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth);\r
3451\r
3452 if (BackUpBuffer != NULL) {\r
3453 FreePool (BackUpBuffer);\r
3454 }\r
3455\r
3456 return ValueChanged;\r
3457}\r
3458\r
3459/**\r
3460 Initialize Question's Edit copy from Storage.\r
3461\r
3462 @param Selection Selection contains the information about \r
3463 the Selection, form and formset to be displayed.\r
3464 Selection action may be updated in retrieve callback.\r
3465 If Selection is NULL, only initialize Question value.\r
3466 @param FormSet FormSet data structure.\r
3467 @param Form Form data structure.\r
3468\r
3469 @retval EFI_SUCCESS The function completed successfully.\r
3470\r
3471**/\r
3472EFI_STATUS\r
3473LoadFormConfig (\r
3474 IN OUT UI_MENU_SELECTION *Selection,\r
3475 IN FORM_BROWSER_FORMSET *FormSet,\r
3476 IN FORM_BROWSER_FORM *Form\r
3477 )\r
3478{\r
3479 EFI_STATUS Status;\r
3480 LIST_ENTRY *Link;\r
3481 FORM_BROWSER_STATEMENT *Question;\r
3482 UINT8 *BufferValue;\r
3483 UINTN StorageWidth;\r
3484 \r
3485 Link = GetFirstNode (&Form->StatementListHead);\r
3486 while (!IsNull (&Form->StatementListHead, Link)) {\r
3487 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
3488\r
3489 //\r
3490 // Initialize local copy of Value for each Question\r
3491 //\r
3492 if (Question->Operand == EFI_IFR_PASSWORD_OP && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)== 0) {\r
3493 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver);\r
3494 } else {\r
3495 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);\r
3496 }\r
3497 if (EFI_ERROR (Status)) {\r
3498 return Status;\r
3499 }\r
3500\r
3501 if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) {\r
3502 HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);\r
3503 }\r
3504\r
3505 //\r
3506 // Call the Retrieve call back function for all questions.\r
3507 //\r
3508 if ((FormSet->ConfigAccess != NULL) && (Selection != NULL) &&\r
3509 ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) &&\r
3510 !gFinishRetrieveCall) {\r
3511 //\r
3512 // Check QuestionValue does exist.\r
3513 //\r
3514 StorageWidth = Question->StorageWidth;\r
3515 if (Question->BufferValue != NULL) {\r
3516 BufferValue = Question->BufferValue;\r
3517 } else {\r
3518 BufferValue = (UINT8 *) &Question->HiiValue.Value;\r
3519 }\r
3520\r
3521 //\r
3522 // For efivarstore storage, initial question value first.\r
3523 //\r
3524 if ((Question->Storage != NULL) && (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {\r
3525 Status = gRT->GetVariable (\r
3526 Question->VariableName,\r
3527 &Question->Storage->Guid,\r
3528 NULL,\r
3529 &StorageWidth,\r
3530 BufferValue\r
3531 );\r
3532 }\r
3533\r
3534 Status = ProcessCallBackFunction(Selection, FormSet, Form, Question, EFI_BROWSER_ACTION_RETRIEVE, TRUE);\r
3535 }\r
3536\r
3537 //\r
3538 // Update Question Value changed flag.\r
3539 //\r
3540 Question->ValueChanged = IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBuffer);\r
3541\r
3542 Link = GetNextNode (&Form->StatementListHead, Link);\r
3543 }\r
3544\r
3545 return EFI_SUCCESS;\r
3546}\r
3547\r
3548/**\r
3549 Initialize Question's Edit copy from Storage for the whole Formset.\r
3550\r
3551 @param Selection Selection contains the information about \r
3552 the Selection, form and formset to be displayed.\r
3553 Selection action may be updated in retrieve callback.\r
3554 If Selection is NULL, only initialize Question value.\r
3555 @param FormSet FormSet data structure.\r
3556\r
3557 @retval EFI_SUCCESS The function completed successfully.\r
3558\r
3559**/\r
3560EFI_STATUS\r
3561LoadFormSetConfig (\r
3562 IN OUT UI_MENU_SELECTION *Selection,\r
3563 IN FORM_BROWSER_FORMSET *FormSet\r
3564 )\r
3565{\r
3566 EFI_STATUS Status;\r
3567 LIST_ENTRY *Link;\r
3568 FORM_BROWSER_FORM *Form;\r
3569\r
3570 Link = GetFirstNode (&FormSet->FormListHead);\r
3571 while (!IsNull (&FormSet->FormListHead, Link)) {\r
3572 Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
3573\r
3574 //\r
3575 // Initialize local copy of Value for each Form\r
3576 //\r
3577 Status = LoadFormConfig (Selection, FormSet, Form);\r
3578 if (EFI_ERROR (Status)) {\r
3579 return Status;\r
3580 }\r
3581\r
3582 Link = GetNextNode (&FormSet->FormListHead, Link);\r
3583 }\r
3584\r
3585 //\r
3586 // Finished question initialization.\r
3587 // \r
3588 FormSet->QuestionInited = TRUE;\r
3589\r
3590 return EFI_SUCCESS;\r
3591}\r
3592\r
3593/**\r
3594 Remove the Request element from the Config Request.\r
3595\r
3596 @param Storage Pointer to the browser storage.\r
3597 @param RequestElement The pointer to the Request element.\r
3598\r
3599**/\r
3600VOID\r
3601RemoveElement (\r
3602 IN OUT BROWSER_STORAGE *Storage,\r
3603 IN CHAR16 *RequestElement\r
3604 )\r
3605{\r
3606 CHAR16 *NewStr;\r
3607 CHAR16 *DestStr;\r
3608\r
3609 ASSERT (Storage->ConfigRequest != NULL && RequestElement != NULL);\r
3610\r
3611 NewStr = StrStr (Storage->ConfigRequest, RequestElement);\r
3612\r
3613 if (NewStr == NULL) {\r
3614 return;\r
3615 }\r
3616\r
3617 //\r
3618 // Remove this element from this ConfigRequest.\r
3619 //\r
3620 DestStr = NewStr;\r
3621 NewStr += StrLen (RequestElement);\r
3622 CopyMem (DestStr, NewStr, StrSize (NewStr));\r
3623 \r
3624 Storage->SpareStrLen += StrLen (RequestElement); \r
3625}\r
3626\r
3627/**\r
3628 Adjust config request in storage, remove the request elements existed in the input ConfigRequest.\r
3629\r
3630 @param Storage Pointer to the browser storage.\r
3631 @param ConfigRequest The pointer to the Request element.\r
3632\r
3633**/\r
3634VOID\r
3635RemoveConfigRequest (\r
3636 BROWSER_STORAGE *Storage,\r
3637 CHAR16 *ConfigRequest\r
3638 )\r
3639{\r
3640 CHAR16 *RequestElement;\r
3641 CHAR16 *NextRequestElement;\r
3642 CHAR16 *SearchKey;\r
3643\r
3644 //\r
3645 // No request element in it, just return.\r
3646 //\r
3647 if (ConfigRequest == NULL) {\r
3648 return;\r
3649 }\r
3650\r
3651 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
3652 //\r
3653 // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage\r
3654 //\r
3655 SearchKey = L"&";\r
3656 } else {\r
3657 //\r
3658 // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage\r
3659 //\r
3660 SearchKey = L"&OFFSET";\r
3661 }\r
3662\r
3663 //\r
3664 // Find SearchKey storage\r
3665 //\r
3666 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
3667 RequestElement = StrStr (ConfigRequest, L"PATH");\r
3668 ASSERT (RequestElement != NULL);\r
3669 RequestElement = StrStr (RequestElement, SearchKey); \r
3670 } else {\r
3671 RequestElement = StrStr (ConfigRequest, SearchKey);\r
3672 }\r
3673\r
3674 while (RequestElement != NULL) {\r
3675 //\r
3676 // +1 to avoid find header itself.\r
3677 //\r
3678 NextRequestElement = StrStr (RequestElement + 1, SearchKey);\r
3679\r
3680 //\r
3681 // The last Request element in configRequest string.\r
3682 //\r
3683 if (NextRequestElement != NULL) {\r
3684 //\r
3685 // Replace "&" with '\0'.\r
3686 //\r
3687 *NextRequestElement = L'\0';\r
3688 }\r
3689\r
3690 RemoveElement (Storage, RequestElement);\r
3691\r
3692 if (NextRequestElement != NULL) {\r
3693 //\r
3694 // Restore '&' with '\0' for later used.\r
3695 //\r
3696 *NextRequestElement = L'&';\r
3697 }\r
3698\r
3699 RequestElement = NextRequestElement;\r
3700 }\r
3701\r
3702 //\r
3703 // If no request element remain, just remove the ConfigRequest string.\r
3704 //\r
3705 if (StrCmp (Storage->ConfigRequest, Storage->ConfigHdr) == 0) {\r
3706 FreePool (Storage->ConfigRequest);\r
3707 Storage->ConfigRequest = NULL;\r
3708 Storage->SpareStrLen = 0;\r
3709 }\r
3710}\r
3711\r
3712/**\r
3713 Base on the current formset info, clean the ConfigRequest string in browser storage.\r
3714\r
3715 @param FormSet Pointer of the FormSet\r
3716\r
3717**/\r
3718VOID\r
3719CleanBrowserStorage (\r
3720 IN OUT FORM_BROWSER_FORMSET *FormSet\r
3721 )\r
3722{\r
3723 LIST_ENTRY *Link;\r
3724 FORMSET_STORAGE *Storage;\r
3725 CHAR16 *ConfigRequest;\r
3726\r
3727 Link = GetFirstNode (&FormSet->StorageListHead);\r
3728 while (!IsNull (&FormSet->StorageListHead, Link)) {\r
3729 Storage = FORMSET_STORAGE_FROM_LINK (Link);\r
3730 Link = GetNextNode (&FormSet->StorageListHead, Link);\r
3731\r
3732 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
3733 if (Storage->ConfigRequest == NULL || Storage->BrowserStorage->ConfigRequest == NULL) {\r
3734 continue;\r
3735 }\r
3736\r
3737 ConfigRequest = FormSet->QuestionInited ? Storage->ConfigRequest : Storage->ConfigElements;\r
3738 RemoveConfigRequest (Storage->BrowserStorage, ConfigRequest);\r
3739 } else if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER ||\r
3740 Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
3741 if (Storage->BrowserStorage->ConfigRequest != NULL) { \r
3742 FreePool (Storage->BrowserStorage->ConfigRequest);\r
3743 }\r
3744 Storage->BrowserStorage->Initialized = FALSE;\r
3745 }\r
3746 }\r
3747}\r
3748\r
3749/**\r
3750 Check whether current element in the ConfigReqeust string.\r
3751\r
3752 @param BrowserStorage Storage which includes ConfigReqeust.\r
3753 @param RequestElement New element need to check.\r
3754\r
3755 @retval TRUE The Element is in the ConfigReqeust string.\r
3756 @retval FALSE The Element not in the configReqeust String.\r
3757\r
3758**/\r
3759BOOLEAN \r
3760ElementValidation (\r
3761 BROWSER_STORAGE *BrowserStorage,\r
3762 CHAR16 *RequestElement\r
3763 )\r
3764{\r
3765 return StrStr (BrowserStorage->ConfigRequest, RequestElement) != NULL ? TRUE : FALSE;\r
3766}\r
3767\r
3768/**\r
3769 Append the Request element to the Config Request.\r
3770\r
3771 @param ConfigRequest Current ConfigRequest info.\r
3772 @param SpareStrLen Current remain free buffer for config reqeust.\r
3773 @param RequestElement New Request element.\r
3774\r
3775**/\r
3776VOID\r
3777AppendConfigRequest (\r
3778 IN OUT CHAR16 **ConfigRequest,\r
3779 IN OUT UINTN *SpareStrLen,\r
3780 IN CHAR16 *RequestElement\r
3781 )\r
3782{\r
3783 CHAR16 *NewStr;\r
3784 UINTN StringSize;\r
3785 UINTN StrLength;\r
3786\r
3787 StrLength = StrLen (RequestElement);\r
3788\r
3789 //\r
3790 // Append <RequestElement> to <ConfigRequest>\r
3791 //\r
3792 if (StrLength > *SpareStrLen) {\r
3793 //\r
3794 // Old String buffer is not sufficient for RequestElement, allocate a new one\r
3795 //\r
3796 StringSize = (*ConfigRequest != NULL) ? StrSize (*ConfigRequest) : sizeof (CHAR16);\r
3797 NewStr = AllocateZeroPool (StringSize + CONFIG_REQUEST_STRING_INCREMENTAL * sizeof (CHAR16));\r
3798 ASSERT (NewStr != NULL);\r
3799\r
3800 if (*ConfigRequest != NULL) {\r
3801 CopyMem (NewStr, *ConfigRequest, StringSize);\r
3802 FreePool (*ConfigRequest);\r
3803 }\r
3804 *ConfigRequest = NewStr;\r
3805 *SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL;\r
3806 }\r
3807\r
3808 StrCat (*ConfigRequest, RequestElement);\r
3809 *SpareStrLen -= StrLength;\r
3810}\r
3811\r
3812/**\r
3813 Adjust the config request info, remove the request elements which already in AllConfigRequest string.\r
3814\r
3815 @param Storage Form set Storage.\r
3816\r
3817 @retval TRUE Has element not covered by current used elements, need to continue to call ExtractConfig\r
3818 @retval FALSE All elements covered by current used elements.\r
3819\r
3820**/\r
3821BOOLEAN \r
3822ConfigRequestAdjust (\r
3823 IN FORMSET_STORAGE *Storage\r
3824 )\r
3825{\r
3826 CHAR16 *RequestElement;\r
3827 CHAR16 *NextRequestElement;\r
3828 CHAR16 *RetBuf;\r
3829 UINTN SpareBufLen;\r
3830 CHAR16 *SearchKey;\r
3831 BOOLEAN RetVal;\r
3832\r
3833 SpareBufLen = 0;\r
3834 RetBuf = NULL;\r
3835 RetVal = FALSE;\r
3836\r
3837 if (Storage->BrowserStorage->ConfigRequest == NULL) {\r
3838 Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);\r
3839 if (Storage->ConfigElements != NULL) {\r
3840 FreePool (Storage->ConfigElements);\r
3841 }\r
3842 Storage->ConfigElements = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);\r
3843 return TRUE;\r
3844 }\r
3845\r
3846 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
3847 //\r
3848 // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage\r
3849 //\r
3850 SearchKey = L"&";\r
3851 } else {\r
3852 //\r
3853 // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage\r
3854 //\r
3855 SearchKey = L"&OFFSET";\r
3856 }\r
3857\r
3858 //\r
3859 // Prepare the config header.\r
3860 // \r
3861 RetBuf = AllocateCopyPool(StrSize (Storage->BrowserStorage->ConfigHdr), Storage->BrowserStorage->ConfigHdr);\r
3862 ASSERT (RetBuf != NULL);\r
3863\r
3864 //\r
3865 // Find SearchKey storage\r
3866 //\r
3867 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
3868 RequestElement = StrStr (Storage->ConfigRequest, L"PATH");\r
3869 ASSERT (RequestElement != NULL);\r
3870 RequestElement = StrStr (RequestElement, SearchKey); \r
3871 } else {\r
3872 RequestElement = StrStr (Storage->ConfigRequest, SearchKey);\r
3873 }\r
3874\r
3875 while (RequestElement != NULL) {\r
3876 //\r
3877 // +1 to avoid find header itself.\r
3878 //\r
3879 NextRequestElement = StrStr (RequestElement + 1, SearchKey);\r
3880\r
3881 //\r
3882 // The last Request element in configRequest string.\r
3883 //\r
3884 if (NextRequestElement != NULL) {\r
3885 //\r
3886 // Replace "&" with '\0'.\r
3887 //\r
3888 *NextRequestElement = L'\0';\r
3889 }\r
3890 \r
3891 if (!ElementValidation (Storage->BrowserStorage, RequestElement)) {\r
3892 //\r
3893 // Add this element to the Storage->BrowserStorage->AllRequestElement.\r
3894 //\r
3895 AppendConfigRequest(&Storage->BrowserStorage->ConfigRequest, &Storage->BrowserStorage->SpareStrLen, RequestElement);\r
3896 AppendConfigRequest (&RetBuf, &SpareBufLen, RequestElement);\r
3897 RetVal = TRUE;\r
3898 }\r
3899\r
3900 if (NextRequestElement != NULL) {\r
3901 //\r
3902 // Restore '&' with '\0' for later used.\r
3903 //\r
3904 *NextRequestElement = L'&';\r
3905 }\r
3906\r
3907 RequestElement = NextRequestElement;\r
3908 }\r
3909\r
3910 if (RetVal) {\r
3911 if (Storage->ConfigElements != NULL) {\r
3912 FreePool (Storage->ConfigElements);\r
3913 }\r
3914 Storage->ConfigElements = RetBuf;\r
3915 } else {\r
3916 FreePool (RetBuf);\r
3917 }\r
3918\r
3919 return RetVal;\r
3920}\r
3921\r
3922/**\r
3923\r
3924 Base on ConfigRequest info to get default value for current formset. \r
3925\r
3926 ConfigRequest info include the info about which questions in current formset need to \r
3927 get default value. This function only get these questions default value.\r
3928 \r
3929 @param FormSet FormSet data structure.\r
3930 @param Storage Storage need to update value.\r
3931 @param ConfigRequest The config request string.\r
3932\r
3933**/\r
3934VOID\r
3935GetDefaultForFormset (\r
3936 IN FORM_BROWSER_FORMSET *FormSet,\r
3937 IN BROWSER_STORAGE *Storage,\r
3938 IN CHAR16 *ConfigRequest\r
3939 )\r
3940{\r
3941 UINT8 *BackUpBuf;\r
3942 UINTN BufferSize;\r
3943 LIST_ENTRY BackUpList;\r
3944 NAME_VALUE_NODE *Node;\r
3945 LIST_ENTRY *Link;\r
3946 LIST_ENTRY *NodeLink;\r
3947 NAME_VALUE_NODE *TmpNode;\r
3948 EFI_STATUS Status;\r
3949 EFI_STRING Progress;\r
3950 EFI_STRING Result;\r
3951\r
3952 BackUpBuf = NULL;\r
3953 InitializeListHead(&BackUpList);\r
3954\r
3955 //\r
3956 // Back update the edit buffer.\r
3957 // \r
3958 if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
3959 (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {\r
3960 BackUpBuf = AllocateCopyPool (Storage->Size, Storage->EditBuffer);\r
3961 ASSERT (BackUpBuf != NULL);\r
3962 } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
3963 Link = GetFirstNode (&Storage->NameValueListHead);\r
3964 while (!IsNull (&Storage->NameValueListHead, Link)) {\r
3965 Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
3966 Link = GetNextNode (&Storage->NameValueListHead, Link);\r
3967\r
3968 //\r
3969 // Only back Node belong to this formset.\r
3970 //\r
3971 if (StrStr (Storage->ConfigRequest, Node->Name) == NULL) {\r
3972 continue;\r
3973 }\r
3974\r
3975 TmpNode = AllocateCopyPool (sizeof (NAME_VALUE_NODE), Node);\r
3976 TmpNode->Name = AllocateCopyPool (StrSize(Node->Name) * sizeof (CHAR16), Node->Name);\r
3977 TmpNode->EditValue = AllocateCopyPool (StrSize(Node->EditValue) * sizeof (CHAR16), Node->EditValue);\r
3978\r
3979 InsertTailList(&BackUpList, &TmpNode->Link);\r
3980 }\r
3981 }\r
3982\r
3983 //\r
3984 // Get default value.\r
3985 //\r
3986 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage, TRUE);\r
3987\r
3988 //\r
3989 // Update the question value based on the input ConfigRequest.\r
3990 //\r
3991 if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
3992 (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {\r
3993 ASSERT (BackUpBuf != NULL);\r
3994 BufferSize = Storage->Size;\r
3995 Status = mHiiConfigRouting->BlockToConfig(\r
3996 mHiiConfigRouting,\r
3997 ConfigRequest,\r
3998 Storage->EditBuffer,\r
3999 BufferSize,\r
4000 &Result,\r
4001 &Progress\r
4002 );\r
4003 ASSERT_EFI_ERROR (Status);\r
4004 \r
4005 Status = mHiiConfigRouting->ConfigToBlock (\r
4006 mHiiConfigRouting,\r
4007 Result,\r
4008 BackUpBuf,\r
4009 &BufferSize,\r
4010 &Progress\r
4011 );\r
4012 ASSERT_EFI_ERROR (Status);\r
4013\r
4014 if (Result != NULL) {\r
4015 FreePool (Result);\r
4016 }\r
4017 \r
4018 CopyMem (Storage->EditBuffer, BackUpBuf, Storage->Size);\r
4019 FreePool (BackUpBuf);\r
4020 } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
4021 //\r
4022 // Update question value, only element in ConfigReqeust will be update.\r
4023 //\r
4024 Link = GetFirstNode (&BackUpList);\r
4025 while (!IsNull (&BackUpList, Link)) {\r
4026 Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
4027 Link = GetNextNode (&BackUpList, Link);\r
4028\r
4029 if (StrStr (ConfigRequest, Node->Name) != NULL) {\r
4030 continue;\r
4031 }\r
4032\r
4033 NodeLink = GetFirstNode (&Storage->NameValueListHead);\r
4034 while (!IsNull (&Storage->NameValueListHead, NodeLink)) {\r
4035 TmpNode = NAME_VALUE_NODE_FROM_LINK (NodeLink);\r
4036 NodeLink = GetNextNode (&Storage->NameValueListHead, NodeLink);\r
4037 \r
4038 if (StrCmp (Node->Name, TmpNode->Name) != 0) {\r
4039 continue;\r
4040 }\r
4041\r
4042 FreePool (TmpNode->EditValue);\r
4043 TmpNode->EditValue = AllocateCopyPool (StrSize(Node->EditValue) * sizeof (CHAR16), Node->EditValue);\r
4044\r
4045 RemoveEntryList (&Node->Link);\r
4046 FreePool (Node->EditValue);\r
4047 FreePool (Node->Name);\r
4048 FreePool (Node);\r
4049 }\r
4050 }\r
4051\r
4052 //\r
4053 // Restore the Name/Value node.\r
4054 // \r
4055 Link = GetFirstNode (&BackUpList);\r
4056 while (!IsNull (&BackUpList, Link)) {\r
4057 Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
4058 Link = GetNextNode (&BackUpList, Link);\r
4059 \r
4060 //\r
4061 // Free this node.\r
4062 //\r
4063 RemoveEntryList (&Node->Link);\r
4064 FreePool (Node->EditValue);\r
4065 FreePool (Node->Name);\r
4066 FreePool (Node);\r
4067 }\r
4068 }\r
4069}\r
4070\r
4071/**\r
4072 Fill storage's edit copy with settings requested from Configuration Driver.\r
4073\r
4074 @param FormSet FormSet data structure.\r
4075 @param Storage Buffer Storage.\r
4076\r
4077**/\r
4078VOID\r
4079LoadStorage (\r
4080 IN FORM_BROWSER_FORMSET *FormSet,\r
4081 IN FORMSET_STORAGE *Storage\r
4082 )\r
4083{\r
4084 EFI_STATUS Status;\r
4085 EFI_STRING Progress;\r
4086 EFI_STRING Result;\r
4087 CHAR16 *StrPtr;\r
4088 EFI_STRING ConfigRequest;\r
4089 UINTN StrLen;\r
4090\r
4091 ConfigRequest = NULL;\r
4092\r
4093 switch (Storage->BrowserStorage->Type) {\r
4094 case EFI_HII_VARSTORE_EFI_VARIABLE:\r
4095 return;\r
4096\r
4097 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:\r
4098 if (Storage->BrowserStorage->ConfigRequest != NULL) {\r
4099 ConfigRequestAdjust(Storage);\r
4100 return;\r
4101 }\r
4102\r
4103 //\r
4104 // Create the config request string to get all fields for this storage.\r
4105 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template\r
4106 // followed by "&OFFSET=0&WIDTH=WWWW"followed by a Null-terminator\r
4107 //\r
4108 StrLen = StrSize (Storage->BrowserStorage->ConfigHdr) + 20 * sizeof (CHAR16);\r
4109 ConfigRequest = AllocateZeroPool (StrLen);\r
4110 ASSERT (ConfigRequest != NULL);\r
4111 UnicodeSPrint (\r
4112 ConfigRequest, \r
4113 StrLen, \r
4114 L"%s&OFFSET=0&WIDTH=%04x", \r
4115 Storage->BrowserStorage->ConfigHdr,\r
4116 Storage->BrowserStorage->Size);\r
4117 break;\r
4118\r
4119 case EFI_HII_VARSTORE_BUFFER:\r
4120 case EFI_HII_VARSTORE_NAME_VALUE:\r
4121 //\r
4122 // Skip if there is no RequestElement or data has initilized.\r
4123 //\r
4124 if (Storage->ElementCount == 0 || Storage->BrowserStorage->Initialized) {\r
4125 return;\r
4126 }\r
4127 Storage->BrowserStorage->Initialized = TRUE;\r
4128 ConfigRequest = Storage->ConfigRequest;\r
4129 break;\r
4130\r
4131 default:\r
4132 return;\r
4133 }\r
4134\r
4135 //\r
4136 // Request current settings from Configuration Driver\r
4137 //\r
4138 Status = mHiiConfigRouting->ExtractConfig (\r
4139 mHiiConfigRouting,\r
4140 ConfigRequest,\r
4141 &Progress,\r
4142 &Result\r
4143 );\r
4144\r
4145 //\r
4146 // If get value fail, extract default from IFR binary\r
4147 //\r
4148 if (EFI_ERROR (Status)) {\r
4149 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE);\r
4150 } else {\r
4151 //\r
4152 // Convert Result from <ConfigAltResp> to <ConfigResp>\r
4153 //\r
4154 StrPtr = StrStr (Result, L"&GUID=");\r
4155 if (StrPtr != NULL) {\r
4156 *StrPtr = L'\0';\r
4157 }\r
4158 \r
4159 Status = ConfigRespToStorage (Storage->BrowserStorage, Result);\r
4160 FreePool (Result);\r
4161 }\r
4162\r
4163 Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);\r
4164\r
4165 //\r
4166 // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer. \r
4167 //\r
4168 SynchronizeStorage(FormSet, Storage->BrowserStorage, NULL, TRUE);\r
4169\r
4170 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
4171 if (ConfigRequest != NULL) {\r
4172 FreePool (ConfigRequest);\r
4173 }\r
4174 }\r
4175}\r
4176\r
4177/**\r
4178 Get current setting of Questions.\r
4179\r
4180 @param FormSet FormSet data structure.\r
4181\r
4182**/\r
4183VOID\r
4184InitializeCurrentSetting (\r
4185 IN OUT FORM_BROWSER_FORMSET *FormSet\r
4186 )\r
4187{\r
4188 LIST_ENTRY *Link;\r
4189 FORMSET_STORAGE *Storage;\r
4190 FORM_BROWSER_FORMSET *OldFormSet;\r
4191\r
4192 //\r
4193 // Try to find pre FormSet in the maintain backup list.\r
4194 // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList.\r
4195 //\r
4196 OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle);\r
4197 if (OldFormSet != NULL) {\r
4198 RemoveEntryList (&OldFormSet->Link);\r
4199 DestroyFormSet (OldFormSet);\r
4200 }\r
4201 InsertTailList (&gBrowserFormSetList, &FormSet->Link);\r
4202\r
4203 //\r
4204 // Extract default from IFR binary for no storage questions.\r
4205 // \r
4206 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE);\r
4207\r
4208 //\r
4209 // Request current settings from Configuration Driver\r
4210 //\r
4211 Link = GetFirstNode (&FormSet->StorageListHead);\r
4212 while (!IsNull (&FormSet->StorageListHead, Link)) {\r
4213 Storage = FORMSET_STORAGE_FROM_LINK (Link);\r
4214\r
4215 LoadStorage (FormSet, Storage);\r
4216\r
4217 Link = GetNextNode (&FormSet->StorageListHead, Link);\r
4218 }\r
4219}\r
4220\r
4221\r
4222/**\r
4223 Fetch the Ifr binary data of a FormSet.\r
4224\r
4225 @param Handle PackageList Handle\r
4226 @param FormSetGuid On input, GUID or class GUID of a formset. If not\r
4227 specified (NULL or zero GUID), take the first\r
4228 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID\r
4229 found in package list.\r
4230 On output, GUID of the formset found(if not NULL).\r
4231 @param BinaryLength The length of the FormSet IFR binary.\r
4232 @param BinaryData The buffer designed to receive the FormSet.\r
4233\r
4234 @retval EFI_SUCCESS Buffer filled with the requested FormSet.\r
4235 BufferLength was updated.\r
4236 @retval EFI_INVALID_PARAMETER The handle is unknown.\r
4237 @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot\r
4238 be found with the requested FormId.\r
4239\r
4240**/\r
4241EFI_STATUS\r
4242GetIfrBinaryData (\r
4243 IN EFI_HII_HANDLE Handle,\r
4244 IN OUT EFI_GUID *FormSetGuid,\r
4245 OUT UINTN *BinaryLength,\r
4246 OUT UINT8 **BinaryData\r
4247 )\r
4248{\r
4249 EFI_STATUS Status;\r
4250 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;\r
4251 UINTN BufferSize;\r
4252 UINT8 *Package;\r
4253 UINT8 *OpCodeData;\r
4254 UINT32 Offset;\r
4255 UINT32 Offset2;\r
4256 UINT32 PackageListLength;\r
4257 EFI_HII_PACKAGE_HEADER PackageHeader;\r
4258 UINT8 Index;\r
4259 UINT8 NumberOfClassGuid;\r
4260 BOOLEAN ClassGuidMatch;\r
4261 EFI_GUID *ClassGuid;\r
4262 EFI_GUID *ComparingGuid;\r
4263\r
4264 OpCodeData = NULL;\r
4265 Package = NULL;\r
4266 ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));\r
4267\r
4268 //\r
4269 // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list\r
4270 //\r
4271 if (FormSetGuid == NULL) {\r
4272 ComparingGuid = &gZeroGuid;\r
4273 } else {\r
4274 ComparingGuid = FormSetGuid;\r
4275 }\r
4276\r
4277 //\r
4278 // Get HII PackageList\r
4279 //\r
4280 BufferSize = 0;\r
4281 HiiPackageList = NULL;\r
4282 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);\r
4283 if (Status == EFI_BUFFER_TOO_SMALL) {\r
4284 HiiPackageList = AllocatePool (BufferSize);\r
4285 ASSERT (HiiPackageList != NULL);\r
4286\r
4287 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);\r
4288 }\r
4289 if (EFI_ERROR (Status)) {\r
4290 return Status;\r
4291 }\r
4292 ASSERT (HiiPackageList != NULL);\r
4293\r
4294 //\r
4295 // Get Form package from this HII package List\r
4296 //\r
4297 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
4298 Offset2 = 0;\r
4299 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));\r
4300\r
4301 ClassGuidMatch = FALSE;\r
4302 while (Offset < PackageListLength) {\r
4303 Package = ((UINT8 *) HiiPackageList) + Offset;\r
4304 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
4305\r
4306 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {\r
4307 //\r
4308 // Search FormSet in this Form Package\r
4309 //\r
4310 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);\r
4311 while (Offset2 < PackageHeader.Length) {\r
4312 OpCodeData = Package + Offset2;\r
4313\r
4314 if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {\r
4315 //\r
4316 // Try to compare against formset GUID\r
4317 //\r
4318 if (CompareGuid (FormSetGuid, &gZeroGuid) || \r
4319 CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {\r
4320 break;\r
4321 }\r
4322\r
4323 if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {\r
4324 //\r
4325 // Try to compare against formset class GUID\r
4326 //\r
4327 NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);\r
4328 ClassGuid = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));\r
4329 for (Index = 0; Index < NumberOfClassGuid; Index++) {\r
4330 if (CompareGuid (ComparingGuid, ClassGuid + Index)) {\r
4331 ClassGuidMatch = TRUE;\r
4332 break;\r
4333 }\r
4334 }\r
4335 if (ClassGuidMatch) {\r
4336 break;\r
4337 }\r
4338 } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {\r
4339 ClassGuidMatch = TRUE;\r
4340 break;\r
4341 }\r
4342 }\r
4343\r
4344 Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;\r
4345 }\r
4346\r
4347 if (Offset2 < PackageHeader.Length) {\r
4348 //\r
4349 // Target formset found\r
4350 //\r
4351 break;\r
4352 }\r
4353 }\r
4354\r
4355 Offset += PackageHeader.Length;\r
4356 }\r
4357\r
4358 if (Offset >= PackageListLength) {\r
4359 //\r
4360 // Form package not found in this Package List\r
4361 //\r
4362 FreePool (HiiPackageList);\r
4363 return EFI_NOT_FOUND;\r
4364 }\r
4365\r
4366 if (FormSetGuid != NULL) {\r
4367 //\r
4368 // Return the FormSet GUID\r
4369 //\r
4370 CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));\r
4371 }\r
4372\r
4373 //\r
4374 // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes\r
4375 // in this FormSet; So, here just simply copy the data from start of a FormSet to the end\r
4376 // of the Form Package.\r
4377 //\r
4378 *BinaryLength = PackageHeader.Length - Offset2;\r
4379 *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);\r
4380\r
4381 FreePool (HiiPackageList);\r
4382\r
4383 if (*BinaryData == NULL) {\r
4384 return EFI_OUT_OF_RESOURCES;\r
4385 }\r
4386\r
4387 return EFI_SUCCESS;\r
4388}\r
4389\r
4390\r
4391/**\r
4392 Initialize the internal data structure of a FormSet.\r
4393\r
4394 @param Handle PackageList Handle\r
4395 @param FormSetGuid On input, GUID or class GUID of a formset. If not\r
4396 specified (NULL or zero GUID), take the first\r
4397 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID\r
4398 found in package list.\r
4399 On output, GUID of the formset found(if not NULL).\r
4400 @param FormSet FormSet data structure.\r
4401\r
4402 @retval EFI_SUCCESS The function completed successfully.\r
4403 @retval EFI_NOT_FOUND The specified FormSet could not be found.\r
4404\r
4405**/\r
4406EFI_STATUS\r
4407InitializeFormSet (\r
4408 IN EFI_HII_HANDLE Handle,\r
4409 IN OUT EFI_GUID *FormSetGuid,\r
4410 OUT FORM_BROWSER_FORMSET *FormSet\r
4411 )\r
4412{\r
4413 EFI_STATUS Status;\r
4414 EFI_HANDLE DriverHandle;\r
4415\r
4416 Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);\r
4417 if (EFI_ERROR (Status)) {\r
4418 return Status;\r
4419 }\r
4420\r
4421 FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;\r
4422 FormSet->HiiHandle = Handle;\r
4423 CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));\r
4424 FormSet->QuestionInited = FALSE;\r
4425\r
4426 //\r
4427 // Retrieve ConfigAccess Protocol associated with this HiiPackageList\r
4428 //\r
4429 Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);\r
4430 if (EFI_ERROR (Status)) {\r
4431 return Status;\r
4432 }\r
4433 FormSet->DriverHandle = DriverHandle;\r
4434 Status = gBS->HandleProtocol (\r
4435 DriverHandle,\r
4436 &gEfiHiiConfigAccessProtocolGuid,\r
4437 (VOID **) &FormSet->ConfigAccess\r
4438 );\r
4439 if (EFI_ERROR (Status)) {\r
4440 //\r
4441 // Configuration Driver don't attach ConfigAccess protocol to its HII package\r
4442 // list, then there will be no configuration action required\r
4443 //\r
4444 FormSet->ConfigAccess = NULL;\r
4445 }\r
4446\r
4447 //\r
4448 // Parse the IFR binary OpCodes\r
4449 //\r
4450 Status = ParseOpCodes (FormSet);\r
4451\r
4452 return Status;\r
4453}\r
4454\r
4455\r
4456/**\r
4457 Save globals used by previous call to SendForm(). SendForm() may be called from \r
4458 HiiConfigAccess.Callback(), this will cause SendForm() be reentried.\r
4459 So, save globals of previous call to SendForm() and restore them upon exit.\r
4460\r
4461**/\r
4462VOID\r
4463SaveBrowserContext (\r
4464 VOID\r
4465 )\r
4466{\r
4467 BROWSER_CONTEXT *Context;\r
4468 FORM_ENTRY_INFO *MenuList;\r
4469\r
4470 gBrowserContextCount++;\r
4471 if (gBrowserContextCount == 1) {\r
4472 //\r
4473 // This is not reentry of SendForm(), no context to save\r
4474 //\r
4475 return;\r
4476 }\r
4477\r
4478 Context = AllocatePool (sizeof (BROWSER_CONTEXT));\r
4479 ASSERT (Context != NULL);\r
4480\r
4481 Context->Signature = BROWSER_CONTEXT_SIGNATURE;\r
4482\r
4483 //\r
4484 // Save FormBrowser context\r
4485 //\r
4486 Context->Selection = gCurrentSelection;\r
4487 Context->ResetRequired = gResetRequired;\r
4488 Context->ExitRequired = gExitRequired;\r
4489 Context->HiiHandle = mCurrentHiiHandle;\r
4490 Context->FormId = mCurrentFormId;\r
4491 CopyGuid (&Context->FormSetGuid, &mCurrentFormSetGuid);\r
4492\r
4493 //\r
4494 // Save the menu history data.\r
4495 //\r
4496 InitializeListHead(&Context->FormHistoryList);\r
4497 while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {\r
4498 MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);\r
4499 RemoveEntryList (&MenuList->Link);\r
4500\r
4501 InsertTailList(&Context->FormHistoryList, &MenuList->Link);\r
4502 }\r
4503\r
4504 //\r
4505 // Insert to FormBrowser context list\r
4506 //\r
4507 InsertHeadList (&gBrowserContextList, &Context->Link);\r
4508}\r
4509\r
4510\r
4511/**\r
4512 Restore globals used by previous call to SendForm().\r
4513\r
4514**/\r
4515VOID\r
4516RestoreBrowserContext (\r
4517 VOID\r
4518 )\r
4519{\r
4520 LIST_ENTRY *Link;\r
4521 BROWSER_CONTEXT *Context;\r
4522 FORM_ENTRY_INFO *MenuList;\r
4523\r
4524 ASSERT (gBrowserContextCount != 0);\r
4525 gBrowserContextCount--;\r
4526 if (gBrowserContextCount == 0) {\r
4527 //\r
4528 // This is not reentry of SendForm(), no context to restore\r
4529 //\r
4530 return;\r
4531 }\r
4532\r
4533 ASSERT (!IsListEmpty (&gBrowserContextList));\r
4534\r
4535 Link = GetFirstNode (&gBrowserContextList);\r
4536 Context = BROWSER_CONTEXT_FROM_LINK (Link);\r
4537\r
4538 //\r
4539 // Restore FormBrowser context\r
4540 //\r
4541 gCurrentSelection = Context->Selection;\r
4542 gResetRequired = Context->ResetRequired;\r
4543 gExitRequired = Context->ExitRequired;\r
4544 mCurrentHiiHandle = Context->HiiHandle;\r
4545 mCurrentFormId = Context->FormId;\r
4546 CopyGuid (&mCurrentFormSetGuid, &Context->FormSetGuid);\r
4547\r
4548 //\r
4549 // Restore the menu history data.\r
4550 //\r
4551 while (!IsListEmpty (&Context->FormHistoryList)) {\r
4552 MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink);\r
4553 RemoveEntryList (&MenuList->Link);\r
4554\r
4555 InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);\r
4556 }\r
4557\r
4558 //\r
4559 // Remove from FormBrowser context list\r
4560 //\r
4561 RemoveEntryList (&Context->Link);\r
4562 gBS->FreePool (Context);\r
4563}\r
4564\r
4565/**\r
4566 Find the matched FormSet context in the backup maintain list based on HiiHandle.\r
4567 \r
4568 @param Handle The Hii Handle.\r
4569 \r
4570 @return the found FormSet context. If no found, NULL will return.\r
4571\r
4572**/\r
4573FORM_BROWSER_FORMSET * \r
4574GetFormSetFromHiiHandle (\r
4575 EFI_HII_HANDLE Handle\r
4576 )\r
4577{\r
4578 LIST_ENTRY *Link;\r
4579 FORM_BROWSER_FORMSET *FormSet;\r
4580\r
4581 Link = GetFirstNode (&gBrowserFormSetList);\r
4582 while (!IsNull (&gBrowserFormSetList, Link)) {\r
4583 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
4584 Link = GetNextNode (&gBrowserFormSetList, Link);\r
4585 if (!ValidateFormSet(FormSet)) {\r
4586 continue;\r
4587 }\r
4588 if (FormSet->HiiHandle == Handle) {\r
4589 return FormSet;\r
4590 }\r
4591 }\r
4592 \r
4593 return NULL;\r
4594}\r
4595\r
4596/**\r
4597 Check whether the input HII handle is the FormSet that is being used.\r
4598 \r
4599 @param Handle The Hii Handle.\r
4600 \r
4601 @retval TRUE HII handle is being used.\r
4602 @retval FALSE HII handle is not being used.\r
4603\r
4604**/\r
4605BOOLEAN\r
4606IsHiiHandleInBrowserContext (\r
4607 EFI_HII_HANDLE Handle\r
4608 )\r
4609{\r
4610 LIST_ENTRY *Link;\r
4611 BROWSER_CONTEXT *Context;\r
4612\r
4613 //\r
4614 // HiiHandle is Current FormSet.\r
4615 //\r
4616 if (mCurrentHiiHandle == Handle) {\r
4617 return TRUE;\r
4618 }\r
4619\r
4620 //\r
4621 // Check whether HiiHandle is in BrowserContext.\r
4622 //\r
4623 Link = GetFirstNode (&gBrowserContextList);\r
4624 while (!IsNull (&gBrowserContextList, Link)) {\r
4625 Context = BROWSER_CONTEXT_FROM_LINK (Link);\r
4626 if (Context->HiiHandle == Handle) {\r
4627 //\r
4628 // HiiHandle is in BrowserContext\r
4629 //\r
4630 return TRUE;\r
4631 }\r
4632 Link = GetNextNode (&gBrowserContextList, Link);\r
4633 }\r
4634 \r
4635 return FALSE;\r
4636}\r
4637\r
4638/**\r
4639 Perform Password check. \r
4640 Passwork may be encrypted by driver that requires the specific check.\r
4641 \r
4642 @param Form Form where Password Statement is in.\r
4643 @param Statement Password statement\r
4644 @param PasswordString Password string to be checked. It may be NULL.\r
4645 NULL means to restore password.\r
4646 "" string can be used to checked whether old password does exist.\r
4647 \r
4648 @return Status Status of Password check.\r
4649**/\r
4650EFI_STATUS\r
4651EFIAPI\r
4652PasswordCheck (\r
4653 IN FORM_DISPLAY_ENGINE_FORM *Form,\r
4654 IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,\r
4655 IN EFI_STRING PasswordString OPTIONAL\r
4656 )\r
4657{\r
4658 EFI_STATUS Status;\r
4659 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
4660 EFI_BROWSER_ACTION_REQUEST ActionRequest;\r
4661 EFI_IFR_TYPE_VALUE IfrTypeValue;\r
4662 FORM_BROWSER_STATEMENT *Question;\r
4663\r
4664 ConfigAccess = gCurrentSelection->FormSet->ConfigAccess;\r
4665 Question = GetBrowserStatement(Statement);\r
4666 ASSERT (Question != NULL);\r
4667\r
4668 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) {\r
4669 if (ConfigAccess == NULL) {\r
4670 return EFI_UNSUPPORTED;\r
4671 }\r
4672 } else {\r
4673 if (PasswordString == NULL) {\r
4674 return EFI_SUCCESS;\r
4675 } \r
4676 \r
4677 if (StrnCmp (PasswordString, (CHAR16 *) Question->BufferValue, Question->StorageWidth/sizeof (CHAR16)) == 0) {\r
4678 return EFI_SUCCESS;\r
4679 } else {\r
4680 return EFI_NOT_READY;\r
4681 }\r
4682 }\r
4683 \r
4684 //\r
4685 // Prepare password string in HII database\r
4686 //\r
4687 if (PasswordString != NULL) {\r
4688 IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle);\r
4689 } else {\r
4690 IfrTypeValue.string = 0;\r
4691 }\r
4692\r
4693 //\r
4694 // Send password to Configuration Driver for validation\r
4695 //\r
4696 Status = ConfigAccess->Callback (\r
4697 ConfigAccess,\r
4698 EFI_BROWSER_ACTION_CHANGING,\r
4699 Question->QuestionId,\r
4700 Question->HiiValue.Type,\r
4701 &IfrTypeValue,\r
4702 &ActionRequest\r
4703 );\r
4704\r
4705 //\r
4706 // Remove password string from HII database\r
4707 //\r
4708 if (PasswordString != NULL) {\r
4709 DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle);\r
4710 }\r
4711\r
4712 return Status;\r
4713}\r
4714\r
4715/**\r
4716 Find the registered HotKey based on KeyData.\r
4717 \r
4718 @param[in] KeyData A pointer to a buffer that describes the keystroke\r
4719 information for the hot key.\r
4720\r
4721 @return The registered HotKey context. If no found, NULL will return.\r
4722**/\r
4723BROWSER_HOT_KEY *\r
4724GetHotKeyFromRegisterList (\r
4725 IN EFI_INPUT_KEY *KeyData\r
4726 )\r
4727{\r
4728 LIST_ENTRY *Link;\r
4729 BROWSER_HOT_KEY *HotKey;\r
4730\r
4731 Link = GetFirstNode (&gBrowserHotKeyList);\r
4732 while (!IsNull (&gBrowserHotKeyList, Link)) {\r
4733 HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);\r
4734 if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {\r
4735 return HotKey;\r
4736 }\r
4737 Link = GetNextNode (&gBrowserHotKeyList, Link);\r
4738 }\r
4739 \r
4740 return NULL;\r
4741}\r
4742\r
4743/**\r
4744 Configure what scope the hot key will impact.\r
4745 All hot keys have the same scope. The mixed hot keys with the different level are not supported.\r
4746 If no scope is set, the default scope will be FormSet level.\r
4747 After all registered hot keys are removed, previous Scope can reset to another level.\r
4748 \r
4749 @param[in] Scope Scope level to be set. \r
4750 \r
4751 @retval EFI_SUCCESS Scope is set correctly.\r
4752 @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE. \r
4753 @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have.\r
4754\r
4755**/\r
4756EFI_STATUS\r
4757EFIAPI\r
4758SetScope (\r
4759 IN BROWSER_SETTING_SCOPE Scope\r
4760 )\r
4761{\r
4762 if (Scope >= MaxLevel) {\r
4763 return EFI_INVALID_PARAMETER;\r
4764 }\r
4765\r
4766 //\r
4767 // When no hot key registered in system or on the first setting,\r
4768 // Scope can be set.\r
4769 //\r
4770 if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) {\r
4771 gBrowserSettingScope = Scope;\r
4772 mBrowserScopeFirstSet = FALSE;\r
4773 } else if (Scope != gBrowserSettingScope) {\r
4774 return EFI_UNSUPPORTED;\r
4775 }\r
4776\r
4777 return EFI_SUCCESS;\r
4778}\r
4779\r
4780/**\r
4781 Register the hot key with its browser action, or unregistered the hot key.\r
4782 Only support hot key that is not printable character (control key, function key, etc.).\r
4783 If the action value is zero, the hot key will be unregistered if it has been registered.\r
4784 If the same hot key has been registered, the new action and help string will override the previous ones.\r
4785 \r
4786 @param[in] KeyData A pointer to a buffer that describes the keystroke\r
4787 information for the hot key. Its type is EFI_INPUT_KEY to \r
4788 be supported by all ConsoleIn devices.\r
4789 @param[in] Action Action value that describes what action will be trigged when the hot key is pressed. \r
4790 @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action.\r
4791 @param[in] HelpString Help string that describes the hot key information.\r
4792 Its value may be NULL for the unregistered hot key.\r
4793 \r
4794 @retval EFI_SUCCESS Hot key is registered or unregistered.\r
4795 @retval EFI_INVALID_PARAMETER KeyData is NULL or HelpString is NULL on register.\r
4796 @retval EFI_NOT_FOUND KeyData is not found to be unregistered.\r
4797 @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser.\r
4798**/\r
4799EFI_STATUS\r
4800EFIAPI\r
4801RegisterHotKey (\r
4802 IN EFI_INPUT_KEY *KeyData,\r
4803 IN UINT32 Action,\r
4804 IN UINT16 DefaultId,\r
4805 IN EFI_STRING HelpString OPTIONAL\r
4806 )\r
4807{\r
4808 BROWSER_HOT_KEY *HotKey;\r
4809\r
4810 //\r
4811 // Check input parameters.\r
4812 //\r
4813 if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL || \r
4814 (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) {\r
4815 return EFI_INVALID_PARAMETER;\r
4816 }\r
4817\r
4818 //\r
4819 // Check whether the input KeyData is in BrowserHotKeyList.\r
4820 //\r
4821 HotKey = GetHotKeyFromRegisterList (KeyData);\r
4822 \r
4823 //\r
4824 // Unregister HotKey\r
4825 //\r
4826 if (Action == BROWSER_ACTION_UNREGISTER) {\r
4827 if (HotKey != NULL) {\r
4828 //\r
4829 // The registered HotKey is found. \r
4830 // Remove it from List, and free its resource.\r
4831 //\r
4832 RemoveEntryList (&HotKey->Link);\r
4833 FreePool (HotKey->KeyData);\r
4834 FreePool (HotKey->HelpString);\r
4835 return EFI_SUCCESS;\r
4836 } else {\r
4837 //\r
4838 // The registered HotKey is not found. \r
4839 //\r
4840 return EFI_NOT_FOUND;\r
4841 }\r
4842 }\r
4843 \r
4844 //\r
4845 // Register HotKey into List.\r
4846 //\r
4847 if (HotKey == NULL) {\r
4848 //\r
4849 // Create new Key, and add it into List.\r
4850 //\r
4851 HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY));\r
4852 ASSERT (HotKey != NULL);\r
4853 HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE;\r
4854 HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData);\r
4855 InsertTailList (&gBrowserHotKeyList, &HotKey->Link);\r
4856 }\r
4857\r
4858 //\r
4859 // Fill HotKey information.\r
4860 //\r
4861 HotKey->Action = Action;\r
4862 HotKey->DefaultId = DefaultId;\r
4863 if (HotKey->HelpString != NULL) {\r
4864 FreePool (HotKey->HelpString);\r
4865 }\r
4866 HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString);\r
4867\r
4868 return EFI_SUCCESS;\r
4869}\r
4870\r
4871/**\r
4872 Register Exit handler function. \r
4873 When more than one handler function is registered, the latter one will override the previous one. \r
4874 When NULL handler is specified, the previous Exit handler will be unregistered. \r
4875 \r
4876 @param[in] Handler Pointer to handler function. \r
4877\r
4878**/\r
4879VOID\r
4880EFIAPI\r
4881RegiserExitHandler (\r
4882 IN EXIT_HANDLER Handler\r
4883 )\r
4884{\r
4885 ExitHandlerFunction = Handler;\r
4886 return;\r
4887}\r
4888\r
4889/**\r
4890 Check whether the browser data has been modified.\r
4891\r
4892 @retval TRUE Browser data is modified.\r
4893 @retval FALSE No browser data is modified.\r
4894\r
4895**/\r
4896BOOLEAN\r
4897EFIAPI\r
4898IsBrowserDataModified (\r
4899 VOID\r
4900 )\r
4901{\r
4902 LIST_ENTRY *Link;\r
4903 FORM_BROWSER_FORMSET *FormSet;\r
4904\r
4905 switch (gBrowserSettingScope) {\r
4906 case FormLevel:\r
4907 if (gCurrentSelection == NULL) {\r
4908 return FALSE;\r
4909 }\r
4910 return IsNvUpdateRequiredForForm (gCurrentSelection->Form);\r
4911\r
4912 case FormSetLevel:\r
4913 if (gCurrentSelection == NULL) {\r
4914 return FALSE;\r
4915 }\r
4916 return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet);\r
4917\r
4918 case SystemLevel:\r
4919 Link = GetFirstNode (&gBrowserFormSetList);\r
4920 while (!IsNull (&gBrowserFormSetList, Link)) {\r
4921 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
4922 if (!ValidateFormSet(FormSet)) {\r
4923 continue;\r
4924 }\r
4925\r
4926 if (IsNvUpdateRequiredForFormSet (FormSet)) {\r
4927 return TRUE;\r
4928 }\r
4929 Link = GetNextNode (&gBrowserFormSetList, Link);\r
4930 }\r
4931 return FALSE;\r
4932\r
4933 default:\r
4934 return FALSE;\r
4935 }\r
4936}\r
4937\r
4938/**\r
4939 Execute the action requested by the Action parameter.\r
4940\r
4941 @param[in] Action Execute the request action.\r
4942 @param[in] DefaultId The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT.\r
4943\r
4944 @retval EFI_SUCCESS Execute the request action succss.\r
4945 @retval EFI_INVALID_PARAMETER The input action value is invalid.\r
4946\r
4947**/\r
4948EFI_STATUS \r
4949EFIAPI\r
4950ExecuteAction (\r
4951 IN UINT32 Action,\r
4952 IN UINT16 DefaultId\r
4953 )\r
4954{\r
4955 EFI_STATUS Status;\r
4956 FORM_BROWSER_FORMSET *FormSet;\r
4957 FORM_BROWSER_FORM *Form;\r
4958\r
4959 if (gBrowserSettingScope < SystemLevel && gCurrentSelection == NULL) {\r
4960 return EFI_NOT_READY;\r
4961 }\r
4962\r
4963 Status = EFI_SUCCESS;\r
4964 FormSet = NULL;\r
4965 Form = NULL;\r
4966 if (gBrowserSettingScope < SystemLevel) {\r
4967 FormSet = gCurrentSelection->FormSet;\r
4968 Form = gCurrentSelection->Form; \r
4969 }\r
4970\r
4971 //\r
4972 // Executet the discard action.\r
4973 //\r
4974 if ((Action & BROWSER_ACTION_DISCARD) != 0) {\r
4975 Status = DiscardForm (FormSet, Form, gBrowserSettingScope);\r
4976 if (EFI_ERROR (Status)) {\r
4977 return Status;\r
4978 }\r
4979 }\r
4980\r
4981 //\r
4982 // Executet the difault action.\r
4983 //\r
4984 if ((Action & BROWSER_ACTION_DEFAULT) != 0) {\r
4985 Status = ExtractDefault (FormSet, Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE);\r
4986 if (EFI_ERROR (Status)) {\r
4987 return Status;\r
4988 }\r
4989 }\r
4990\r
4991 //\r
4992 // Executet the submit action.\r
4993 //\r
4994 if ((Action & BROWSER_ACTION_SUBMIT) != 0) {\r
4995 Status = SubmitForm (FormSet, Form, gBrowserSettingScope);\r
4996 if (EFI_ERROR (Status)) {\r
4997 return Status;\r
4998 }\r
4999 }\r
5000\r
5001 //\r
5002 // Executet the reset action.\r
5003 //\r
5004 if ((Action & BROWSER_ACTION_RESET) != 0) {\r
5005 gResetRequired = TRUE;\r
5006 }\r
5007\r
5008 //\r
5009 // Executet the exit action.\r
5010 //\r
5011 if ((Action & BROWSER_ACTION_EXIT) != 0) {\r
5012 DiscardForm (FormSet, Form, gBrowserSettingScope);\r
5013 if (gBrowserSettingScope == SystemLevel) {\r
5014 if (ExitHandlerFunction != NULL) {\r
5015 ExitHandlerFunction ();\r
5016 }\r
5017 }\r
5018\r
5019 gExitRequired = TRUE;\r
5020 }\r
5021\r
5022 return Status;\r
5023}\r
5024\r
5025/**\r
5026 Create reminder to let user to choose save or discard the changed browser data.\r
5027 Caller can use it to actively check the changed browser data.\r
5028\r
5029 @retval BROWSER_NO_CHANGES No browser data is changed.\r
5030 @retval BROWSER_SAVE_CHANGES The changed browser data is saved.\r
5031 @retval BROWSER_DISCARD_CHANGES The changed browser data is discard.\r
5032 @retval BROWSER_KEEP_CURRENT Browser keep current changes.\r
5033\r
5034**/\r
5035UINT32\r
5036EFIAPI\r
5037SaveReminder (\r
5038 VOID\r
5039 )\r
5040{\r
5041 LIST_ENTRY *Link;\r
5042 FORM_BROWSER_FORMSET *FormSet;\r
5043 BOOLEAN IsDataChanged;\r
5044 UINT32 DataSavedAction;\r
5045 UINT32 ConfirmRet;\r
5046\r
5047 DataSavedAction = BROWSER_NO_CHANGES;\r
5048 IsDataChanged = FALSE;\r
5049 Link = GetFirstNode (&gBrowserFormSetList);\r
5050 while (!IsNull (&gBrowserFormSetList, Link)) {\r
5051 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
5052 Link = GetNextNode (&gBrowserFormSetList, Link);\r
5053 if (!ValidateFormSet(FormSet)) {\r
5054 continue;\r
5055 }\r
5056 if (IsNvUpdateRequiredForFormSet (FormSet)) {\r
5057 IsDataChanged = TRUE;\r
5058 break;\r
5059 }\r
5060 }\r
5061 \r
5062 //\r
5063 // No data is changed. No save is required. \r
5064 //\r
5065 if (!IsDataChanged) {\r
5066 return DataSavedAction;\r
5067 }\r
5068 \r
5069 //\r
5070 // If data is changed, prompt user to save or discard it. \r
5071 //\r
5072 do {\r
5073 ConfirmRet = (UINT32) mFormDisplay->ConfirmDataChange();\r
5074\r
5075 if (ConfirmRet == BROWSER_ACTION_SUBMIT) {\r
5076 SubmitForm (NULL, NULL, SystemLevel);\r
5077 DataSavedAction = BROWSER_SAVE_CHANGES;\r
5078 break;\r
5079 } else if (ConfirmRet == BROWSER_ACTION_DISCARD) {\r
5080 DiscardForm (NULL, NULL, SystemLevel);\r
5081 DataSavedAction = BROWSER_DISCARD_CHANGES;\r
5082 break;\r
5083 } else if (ConfirmRet == BROWSER_ACTION_NONE) {\r
5084 DataSavedAction = BROWSER_KEEP_CURRENT;\r
5085 break;\r
5086 }\r
5087 } while (1);\r
5088\r
5089 return DataSavedAction;\r
5090}\r