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