3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Implementation for UI.
41 Set Buffer to Value for Size bytes.
45 Buffer - Memory to set.
47 Size - Number of bytes to set
49 Value - Value of the set operation.
72 Initialize Menu option list.
80 InitializeListHead (&Menu
);
90 Initialize Menu option list.
98 InitializeListHead (&gMenuList
);
102 UiRemoveMenuListEntry (
103 IN UI_MENU_OPTION
*Selection
,
104 OUT UI_MENU_OPTION
**PreviousSelection
109 Remove Menu option list.
117 UI_MENU_LIST
*UiMenuList
;
119 *PreviousSelection
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
120 ASSERT (*PreviousSelection
!= NULL
);
122 if (!IsListEmpty (&gMenuList
)) {
123 UiMenuList
= CR (gMenuList
.ForwardLink
, UI_MENU_LIST
, MenuLink
, UI_MENU_LIST_SIGNATURE
);
124 (*PreviousSelection
)->IfrNumber
= UiMenuList
->Selection
.IfrNumber
;
125 (*PreviousSelection
)->FormId
= UiMenuList
->Selection
.FormId
;
126 (*PreviousSelection
)->Tags
= UiMenuList
->Selection
.Tags
;
127 (*PreviousSelection
)->ThisTag
= UiMenuList
->Selection
.ThisTag
;
128 (*PreviousSelection
)->Handle
= UiMenuList
->Selection
.Handle
;
129 gEntryNumber
= UiMenuList
->FormerEntryNumber
;
130 RemoveEntryList (&UiMenuList
->MenuLink
);
131 gBS
->FreePool (UiMenuList
);
142 Free Menu option linked list.
150 UI_MENU_LIST
*UiMenuList
;
152 while (!IsListEmpty (&gMenuList
)) {
153 UiMenuList
= CR (gMenuList
.ForwardLink
, UI_MENU_LIST
, MenuLink
, UI_MENU_LIST_SIGNATURE
);
154 RemoveEntryList (&UiMenuList
->MenuLink
);
155 gBS
->FreePool (UiMenuList
);
161 IN UI_MENU_OPTION
*Selection
166 Add one menu entry to the linked lst
174 UI_MENU_LIST
*UiMenuList
;
176 UiMenuList
= AllocateZeroPool (sizeof (UI_MENU_LIST
));
177 ASSERT (UiMenuList
!= NULL
);
179 UiMenuList
->Signature
= UI_MENU_LIST_SIGNATURE
;
180 CopyMem (&UiMenuList
->Selection
, Selection
, sizeof (UI_MENU_OPTION
));
182 InsertHeadList (&gMenuList
, &UiMenuList
->MenuLink
);
192 Free Menu option linked list.
200 UI_MENU_OPTION
*MenuOption
;
202 while (!IsListEmpty (&Menu
)) {
203 MenuOption
= CR (Menu
.ForwardLink
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
204 RemoveEntryList (&MenuOption
->Link
);
207 // We allocated space for this description when we did a GetToken, free it here
209 gBS
->FreePool (MenuOption
->Description
);
210 gBS
->FreePool (MenuOption
);
221 Refresh screen with current date and/or time based on screen context
229 CHAR16
*OptionString
;
230 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
236 if (gMenuRefreshHead
!= NULL
) {
238 MenuRefreshEntry
= gMenuRefreshHead
;
241 gST
->ConOut
->SetAttribute (gST
->ConOut
, MenuRefreshEntry
->CurrentAttribute
);
242 ProcessOptions (MenuRefreshEntry
->MenuOption
, FALSE
, MenuRefreshEntry
->FileFormTagsHead
, NULL
, &OptionString
);
244 if (OptionString
!= NULL
) {
246 // If leading spaces on OptionString - remove the spaces
248 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
251 for (Loop
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
252 OptionString
[Loop
] = OptionString
[Index
];
256 OptionString
[Loop
] = CHAR_NULL
;
258 PrintStringAt (MenuRefreshEntry
->CurrentColumn
, MenuRefreshEntry
->CurrentRow
, OptionString
);
261 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
263 } while (MenuRefreshEntry
!= NULL
);
266 if (OptionString
!= NULL
) {
267 gBS
->FreePool (OptionString
);
272 UiWaitForSingleEvent (
274 IN UINT64 Timeout OPTIONAL
279 Wait for a given event to fire, or for an optional timeout to expire.
282 Event - The event to wait for
284 Timeout - An optional timeout value in 100 ns units.
288 EFI_SUCCESS - Event fired before Timeout expired.
289 EFI_TIME_OUT - Timout expired before Event fired.
295 EFI_EVENT TimerEvent
;
296 EFI_EVENT WaitList
[2];
300 // Create a timer event
302 Status
= gBS
->CreateEvent (EFI_EVENT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
303 if (!EFI_ERROR (Status
)) {
305 // Set the timer event
314 // Wait for the original event or the timer
317 WaitList
[1] = TimerEvent
;
318 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
319 gBS
->CloseEvent (TimerEvent
);
322 // If the timer expired, change the return to timed out
324 if (!EFI_ERROR (Status
) && Index
== 1) {
325 Status
= EFI_TIMEOUT
;
330 // Update screen every second
332 Timeout
= ONE_SECOND
;
335 Status
= gBS
->CreateEvent (EFI_EVENT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
338 // Set the timer event
347 // Wait for the original event or the timer
350 WaitList
[1] = TimerEvent
;
351 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
354 // If the timer expired, update anything that needs a refresh and keep waiting
356 if (!EFI_ERROR (Status
) && Index
== 1) {
357 Status
= EFI_TIMEOUT
;
358 UpdateDateAndTime ();
361 gBS
->CloseEvent (TimerEvent
);
362 } while (Status
== EFI_TIMEOUT
);
371 IN EFI_HII_HANDLE Handle
,
379 Add one menu option by specified description and context.
382 String - String description for this option.
383 Context - Context data for entry.
389 UI_MENU_OPTION
*MenuOption
;
391 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
394 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
395 MenuOption
->Description
= String
;
396 MenuOption
->Handle
= Handle
;
397 MenuOption
->FormBinary
= FormBinary
;
398 MenuOption
->IfrNumber
= IfrNumber
;
399 MenuOption
->Skip
= 1;
400 MenuOption
->Tags
= Tags
;
401 MenuOption
->TagIndex
= 0;
402 MenuOption
->ThisTag
= &(MenuOption
->Tags
[MenuOption
->TagIndex
]);
403 MenuOption
->EntryNumber
= (UINT16
) IfrNumber
;
405 InsertTailList (&Menu
, &MenuOption
->Link
);
411 IN EFI_HII_HANDLE Handle
,
415 IN UINT16 MenuItemCount
420 Add one menu option by specified description and context.
423 String - String description for this option.
424 Context - Context data for entry.
430 UI_MENU_OPTION
*MenuOption
;
432 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
435 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
436 MenuOption
->Description
= String
;
437 MenuOption
->Handle
= Handle
;
438 MenuOption
->Skip
= Tags
[TagIndex
].NumberOfLines
;
439 MenuOption
->IfrNumber
= gActiveIfr
;
440 MenuOption
->Tags
= Tags
;
441 MenuOption
->TagIndex
= TagIndex
;
442 MenuOption
->ThisTag
= &(MenuOption
->Tags
[MenuOption
->TagIndex
]);
443 MenuOption
->Consistency
= Tags
[TagIndex
].Consistency
;
444 MenuOption
->FormId
= FormId
;
445 MenuOption
->GrayOut
= Tags
[TagIndex
].GrayOut
;
446 MenuOption
->EntryNumber
= MenuItemCount
;
448 InsertTailList (&Menu
, &MenuOption
->Link
);
453 IN UINTN NumberOfLines
,
455 IN UINTN MaximumStringSize
,
456 OUT CHAR16
*StringBuffer
,
457 OUT EFI_INPUT_KEY
*KeyValue
,
464 Routine used to abstract a generic dialog interface and return the selected key or string
467 NumberOfLines - The number of lines for the dialog box
468 HotKey - Defines whether a single character is parsed (TRUE) and returned in KeyValue
469 or a string is returned in StringBuffer. Two special characters are considered when entering a string, a SCAN_ESC and
470 an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates string input and returns
471 MaximumStringSize - The maximum size in bytes of a typed in string (each character is a CHAR16) and the minimum string returned is two bytes
472 StringBuffer - The passed in pointer to the buffer which will hold the typed in string if HotKey is FALSE
473 KeyValue - The EFI_KEY value returned if HotKey is TRUE..
474 String - Pointer to the first string in the list
475 ... - A series of (quantity == NumberOfLines) text strings which will be used to construct the dialog box
478 EFI_SUCCESS - Displayed dialog and received user interaction
479 EFI_INVALID_PARAMETER - One of the parameters was invalid (e.g. (StringBuffer == NULL) && (HotKey == FALSE))
480 EFI_DEVICE_ERROR - User typed in an ESC character to exit the routine
489 CHAR16
*BufferedString
;
496 BOOLEAN SelectionComplete
;
498 UINTN CurrentAttribute
;
499 UINTN DimensionsWidth
;
500 UINTN DimensionsHeight
;
502 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
503 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
505 SelectionComplete
= FALSE
;
507 TempString
= AllocateZeroPool (MaximumStringSize
* 2);
508 BufferedString
= AllocateZeroPool (MaximumStringSize
* 2);
509 CurrentAttribute
= gST
->ConOut
->Mode
->Attribute
;
512 ASSERT (BufferedString
);
514 VA_START (Marker
, String
);
517 // Zero the outgoing buffer
519 ZeroMem (StringBuffer
, MaximumStringSize
);
522 if (KeyValue
== NULL
) {
523 return EFI_INVALID_PARAMETER
;
526 if (StringBuffer
== NULL
) {
527 return EFI_INVALID_PARAMETER
;
533 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
535 LargestString
= (GetStringWidth (String
) / 2);
537 if (LargestString
== L
' ') {
541 // Determine the largest string in the dialog box
542 // Notice we are starting with 1 since String is the first string
544 for (Count
= 1; Count
< NumberOfLines
; Count
++) {
545 StackString
= VA_ARG (Marker
, CHAR16
*);
547 if (StackString
[0] == L
' ') {
548 InputOffset
= Count
+ 1;
551 if ((GetStringWidth (StackString
) / 2) > LargestString
) {
553 // Size of the string visually and subtract the width by one for the null-terminator
555 LargestString
= (GetStringWidth (StackString
) / 2);
559 Start
= (DimensionsWidth
- LargestString
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
560 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
567 CreateSharedPopUp (LargestString
, NumberOfLines
, &String
);
570 // Take the first key typed and report it back?
573 Status
= WaitForKeyStroke (&Key
);
574 CopyMem (KeyValue
, &Key
, sizeof (EFI_INPUT_KEY
));
578 Status
= WaitForKeyStroke (&Key
);
580 switch (Key
.UnicodeChar
) {
582 switch (Key
.ScanCode
) {
584 gBS
->FreePool (TempString
);
585 gBS
->FreePool (BufferedString
);
586 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
587 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
588 return EFI_DEVICE_ERROR
;
596 case CHAR_CARRIAGE_RETURN
:
597 SelectionComplete
= TRUE
;
598 gBS
->FreePool (TempString
);
599 gBS
->FreePool (BufferedString
);
600 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
601 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
606 if (StringBuffer
[0] != CHAR_NULL
) {
607 for (Index
= 0; StringBuffer
[Index
] != CHAR_NULL
; Index
++) {
608 TempString
[Index
] = StringBuffer
[Index
];
611 // Effectively truncate string by 1 character
613 TempString
[Index
- 1] = CHAR_NULL
;
614 StrCpy (StringBuffer
, TempString
);
619 // If it is the beginning of the string, don't worry about checking maximum limits
621 if ((StringBuffer
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
622 StrnCpy (StringBuffer
, &Key
.UnicodeChar
, 1);
623 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
624 } else if ((GetStringWidth (StringBuffer
) < MaximumStringSize
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
625 KeyPad
[0] = Key
.UnicodeChar
;
626 KeyPad
[1] = CHAR_NULL
;
627 StrCat (StringBuffer
, KeyPad
);
628 StrCat (TempString
, KeyPad
);
631 // If the width of the input string is now larger than the screen, we nee to
632 // adjust the index to start printing portions of the string
634 SetUnicodeMem (BufferedString
, LargestString
, L
' ');
636 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
638 if ((GetStringWidth (StringBuffer
) / 2) > (DimensionsWidth
- 2)) {
639 Index
= (GetStringWidth (StringBuffer
) / 2) - DimensionsWidth
+ 2;
644 for (Count
= 0; Index
+ 1 < GetStringWidth (StringBuffer
) / 2; Index
++, Count
++) {
645 BufferedString
[Count
] = StringBuffer
[Index
];
648 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
651 } while (!SelectionComplete
);
654 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
655 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
661 IN UINTN RequestedWidth
,
662 IN UINTN NumberOfLines
,
663 IN CHAR16
**ArrayOfStrings
675 UINTN DimensionsWidth
;
676 UINTN DimensionsHeight
;
678 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
679 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
683 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
685 if ((RequestedWidth
+ 2) > DimensionsWidth
) {
686 RequestedWidth
= DimensionsWidth
- 2;
689 // Subtract the PopUp width from total Columns, allow for one space extra on
690 // each end plus a border.
692 Start
= (DimensionsWidth
- RequestedWidth
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
693 End
= Start
+ RequestedWidth
+ 1;
695 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
696 Bottom
= Top
+ NumberOfLines
+ 2;
698 Character
= (CHAR16
) BOXDRAW_DOWN_RIGHT
;
699 PrintCharAt (Start
, Top
, Character
);
700 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
701 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
702 PrintChar (Character
);
705 Character
= (CHAR16
) BOXDRAW_DOWN_LEFT
;
706 PrintChar (Character
);
707 Character
= (CHAR16
) BOXDRAW_VERTICAL
;
708 for (Index
= Top
; Index
+ 2 < Bottom
; Index
++) {
709 String
= ArrayOfStrings
[Count
];
713 // This will clear the background of the line - we never know who might have been
714 // here before us. This differs from the next clear in that it used the non-reverse
715 // video for normal printing.
717 if (GetStringWidth (String
) / 2 > 1) {
718 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
721 // Passing in a space results in the assumption that this is where typing will occur
723 if (String
[0] == L
' ') {
724 ClearLines (Start
+ 1, End
- 1, Index
+ 1, Index
+ 1, POPUP_INVERSE_TEXT
| POPUP_INVERSE_BACKGROUND
);
727 // Passing in a NULL results in a blank space
729 if (String
[0] == CHAR_NULL
) {
730 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
734 ((DimensionsWidth
- GetStringWidth (String
) / 2) / 2) + gScreenDimensions
.LeftColumn
+ 1,
738 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
739 PrintCharAt (Start
, Index
+ 1, Character
);
740 PrintCharAt (End
- 1, Index
+ 1, Character
);
743 Character
= (CHAR16
) BOXDRAW_UP_RIGHT
;
744 PrintCharAt (Start
, Bottom
- 1, Character
);
745 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
746 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
747 PrintChar (Character
);
750 Character
= (CHAR16
) BOXDRAW_UP_LEFT
;
751 PrintChar (Character
);
756 IN UINTN RequestedWidth
,
757 IN UINTN NumberOfLines
,
758 IN CHAR16
*ArrayOfStrings
,
762 CreateSharedPopUp (RequestedWidth
, NumberOfLines
, &ArrayOfStrings
);
767 IN UINTN MessageType
,
773 STATIC BOOLEAN InputError
;
774 CHAR16
*NvUpdateMessage
;
775 CHAR16
*InputErrorMessage
;
777 NvUpdateMessage
= GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE
), gHiiHandle
);
778 InputErrorMessage
= GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE
), gHiiHandle
);
780 switch (MessageType
) {
783 gST
->ConOut
->SetAttribute (gST
->ConOut
, ERROR_TEXT
);
785 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
,
786 gScreenDimensions
.BottomRow
- 1,
791 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
);
792 for (Index
= 0; Index
< (GetStringWidth (InputErrorMessage
) - 2) / 2; Index
++) {
793 PrintAt (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ Index
, gScreenDimensions
.BottomRow
- 1, (CHAR16
*) L
" ");
800 case NV_UPDATE_REQUIRED
:
801 if (gClassOfVfr
!= EFI_FRONT_PAGE_SUBCLASS
) {
803 gST
->ConOut
->SetAttribute (gST
->ConOut
, INFO_TEXT
);
805 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
806 gScreenDimensions
.BottomRow
- 1,
809 gResetRequired
= (BOOLEAN
) (gResetRequired
| (Flags
& RESET_REQUIRED
));
811 gNvUpdateRequired
= TRUE
;
813 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
);
814 for (Index
= 0; Index
< (GetStringWidth (NvUpdateMessage
) - 2) / 2; Index
++) {
816 (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ Index
),
817 gScreenDimensions
.BottomRow
- 1,
822 gNvUpdateRequired
= FALSE
;
827 case REFRESH_STATUS_BAR
:
829 UpdateStatusBar (INPUT_ERROR
, Flags
, TRUE
);
832 if (gNvUpdateRequired
) {
833 UpdateStatusBar (NV_UPDATE_REQUIRED
, Flags
, TRUE
);
841 gBS
->FreePool (InputErrorMessage
);
842 gBS
->FreePool (NvUpdateMessage
);
848 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
849 IN CHAR16
*FormattedString
,
850 IN CHAR16
*OptionString
856 Used to remove the allocated data instances
864 EFI_FILE_FORM_TAGS
*FileForm
;
865 EFI_FILE_FORM_TAGS
*PreviousFileForm
;
866 EFI_FORM_TAGS
*FormTags
;
867 EFI_FORM_TAGS
*PreviousFormTags
;
868 EFI_IFR_BINARY
*IfrBinary
;
869 EFI_IFR_BINARY
*PreviousIfrBinary
;
870 EFI_INCONSISTENCY_DATA
*Inconsistent
;
871 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
872 EFI_VARIABLE_DEFINITION
*PreviousVariableDefinition
;
876 FileForm
= FileFormTagsHead
;
878 if (FormattedString
!= NULL
) {
879 gBS
->FreePool (FormattedString
);
882 if (OptionString
!= NULL
) {
883 gBS
->FreePool (OptionString
);
886 for (; FileForm
!= NULL
;) {
887 PreviousFileForm
= NULL
;
890 // Advance FileForm to the last entry
892 for (; FileForm
->NextFile
!= NULL
; FileForm
= FileForm
->NextFile
) {
893 PreviousFileForm
= FileForm
;
896 FormTags
= &FileForm
->FormTags
;
898 for (; FormTags
!= NULL
;) {
899 FormTags
= &FileForm
->FormTags
;
900 PreviousFormTags
= NULL
;
903 // Advance FormTags to the last entry
905 for (; FormTags
->Next
!= NULL
; FormTags
= FormTags
->Next
) {
906 PreviousFormTags
= FormTags
;
909 // Walk through each of the tags and free the IntList allocation
911 for (Index
= 0; FormTags
->Tags
[Index
].Operand
!= EFI_IFR_END_FORM_OP
; Index
++) {
913 // It is more than likely that the very last page will contain an end formset
915 if (FormTags
->Tags
[Index
].Operand
== EFI_IFR_END_FORM_SET_OP
) {
919 if (FormTags
->Tags
[Index
].IntList
!= NULL
) {
920 gBS
->FreePool (FormTags
->Tags
[Index
].IntList
);
924 if (PreviousFormTags
!= NULL
) {
925 gBS
->FreePool (FormTags
->Tags
);
926 FormTags
= PreviousFormTags
;
927 gBS
->FreePool (FormTags
->Next
);
928 FormTags
->Next
= NULL
;
930 gBS
->FreePool (FormTags
->Tags
);
935 // Last FileForm entry's Inconsistent database
937 Inconsistent
= FileForm
->InconsistentTags
;
940 // Advance Inconsistent to the last entry
942 for (; Inconsistent
->Next
!= NULL
; Inconsistent
= Inconsistent
->Next
)
945 for (; Inconsistent
!= NULL
;) {
947 // Preserve the Previous pointer
949 Buffer
= (VOID
*) Inconsistent
->Previous
;
952 // Free the current entry
954 gBS
->FreePool (Inconsistent
);
957 // Restore the Previous pointer
959 Inconsistent
= (EFI_INCONSISTENCY_DATA
*) Buffer
;
962 VariableDefinition
= FileForm
->VariableDefinitions
;
964 for (; VariableDefinition
!= NULL
;) {
965 VariableDefinition
= FileForm
->VariableDefinitions
;
966 PreviousVariableDefinition
= NULL
;
969 // Advance VariableDefinitions to the last entry
971 for (; VariableDefinition
->Next
!= NULL
; VariableDefinition
= VariableDefinition
->Next
) {
972 PreviousVariableDefinition
= VariableDefinition
;
975 gBS
->FreePool (VariableDefinition
->VariableName
);
976 gBS
->FreePool (VariableDefinition
->NvRamMap
);
977 gBS
->FreePool (VariableDefinition
->FakeNvRamMap
);
979 if (PreviousVariableDefinition
!= NULL
) {
980 VariableDefinition
= PreviousVariableDefinition
;
981 gBS
->FreePool (VariableDefinition
->Next
);
982 VariableDefinition
->Next
= NULL
;
984 gBS
->FreePool (VariableDefinition
);
985 VariableDefinition
= NULL
;
989 if (PreviousFileForm
!= NULL
) {
990 FileForm
= PreviousFileForm
;
991 gBS
->FreePool (FileForm
->NextFile
);
992 FileForm
->NextFile
= NULL
;
994 gBS
->FreePool (FileForm
);
999 IfrBinary
= gBinaryDataHead
;
1001 for (; IfrBinary
!= NULL
;) {
1002 IfrBinary
= gBinaryDataHead
;
1003 PreviousIfrBinary
= NULL
;
1006 // Advance IfrBinary to the last entry
1008 for (; IfrBinary
->Next
!= NULL
; IfrBinary
= IfrBinary
->Next
) {
1009 PreviousIfrBinary
= IfrBinary
;
1012 gBS
->FreePool (IfrBinary
->IfrPackage
);
1014 if (PreviousIfrBinary
!= NULL
) {
1015 IfrBinary
= PreviousIfrBinary
;
1016 gBS
->FreePool (IfrBinary
->Next
);
1017 IfrBinary
->Next
= NULL
;
1019 gBS
->FreePool (IfrBinary
);
1024 gBS
->FreePool (gPreviousValue
);
1025 gPreviousValue
= NULL
;
1028 // Free Browser Strings
1030 gBS
->FreePool (gPressEnter
);
1031 gBS
->FreePool (gConfirmError
);
1032 gBS
->FreePool (gConfirmPassword
);
1033 gBS
->FreePool (gPromptForNewPassword
);
1034 gBS
->FreePool (gPromptForPassword
);
1035 gBS
->FreePool (gToggleCheckBox
);
1036 gBS
->FreePool (gNumericInput
);
1037 gBS
->FreePool (gMakeSelection
);
1038 gBS
->FreePool (gMoveHighlight
);
1039 gBS
->FreePool (gEscapeString
);
1040 gBS
->FreePool (gEnterCommitString
);
1041 gBS
->FreePool (gEnterString
);
1042 gBS
->FreePool (gFunctionOneString
);
1043 gBS
->FreePool (gFunctionTwoString
);
1044 gBS
->FreePool (gFunctionNineString
);
1045 gBS
->FreePool (gFunctionTenString
);
1050 SelectionsAreValid (
1051 IN UI_MENU_OPTION
*MenuOption
,
1052 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
1056 Routine Description:
1057 Initiate late consistency checks against the current page.
1068 EFI_FILE_FORM_TAGS
*FileFormTags
;
1070 CHAR16 NullCharacter
;
1076 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
1078 StringPtr
= (CHAR16
*) L
"\0";
1079 NullCharacter
= CHAR_NULL
;
1081 FileFormTags
= FileFormTagsHead
;
1083 for (Index
= 0; Index
< MenuOption
->IfrNumber
; Index
++) {
1084 FileFormTags
= FileFormTags
->NextFile
;
1087 for (Link
= Menu
.ForwardLink
; Link
!= &Menu
; Link
= Link
->ForwardLink
) {
1088 MenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
1090 Tag
= MenuOption
->ThisTag
;
1092 ExtractRequestedNvMap (FileFormTags
, Tag
->VariableNumber
, &VariableDefinition
);
1093 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
1096 // If the op-code has a late check, ensure consistency checks are now applied
1098 if (Tag
->Flags
& EFI_IFR_FLAG_LATE_CHECK
) {
1099 if (ValueIsNotValid (TRUE
, 0, Tag
, FileFormTags
, &PopUp
)) {
1100 if (PopUp
!= 0x0000) {
1101 StringPtr
= GetToken (PopUp
, MenuOption
->Handle
);
1103 CreatePopUp (GetStringWidth (StringPtr
) / 2, 3, &NullCharacter
, StringPtr
, &NullCharacter
);
1106 Status
= WaitForKeyStroke (&Key
);
1108 switch (Key
.UnicodeChar
) {
1110 case CHAR_CARRIAGE_RETURN
:
1112 // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
1114 CopyMem (NvRamMap
, &Tag
->OldValue
, Tag
->StorageWidth
);
1115 gBS
->FreePool (StringPtr
);
1121 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1135 IN EFI_HII_HANDLE Handle
1139 Routine Description:
1140 Get the supported width for a particular op-code
1143 Tag - The Tag structure passed in.
1144 Handle - The handle in the HII database being used
1147 Returns the number of CHAR16 characters that is support.
1158 // See if the second text parameter is really NULL
1160 if ((Tag
->Operand
== EFI_IFR_TEXT_OP
) && (Tag
->TextTwo
!= 0)) {
1161 String
= GetToken (Tag
->TextTwo
, Handle
);
1162 Size
= StrLen (String
);
1163 gBS
->FreePool (String
);
1166 if ((Tag
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1167 (Tag
->Operand
== EFI_IFR_REF_OP
) ||
1168 (Tag
->Operand
== EFI_IFR_PASSWORD_OP
) ||
1169 (Tag
->Operand
== EFI_IFR_STRING_OP
) ||
1170 (Tag
->Operand
== EFI_IFR_INVENTORY_OP
) ||
1172 // Allow a wide display if text op-code and no secondary text op-code
1174 ((Tag
->Operand
== EFI_IFR_TEXT_OP
) && (Size
== 0x0000))
1176 return (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
);
1178 return (UINT16
) gPromptBlockWidth
;
1184 IN CHAR16
*InputString
,
1185 IN UINT16 LineWidth
,
1186 IN OUT UINTN
*Index
,
1187 OUT CHAR16
**OutputString
1191 Routine Description:
1192 Will copy LineWidth amount of a string in the OutputString buffer and return the
1193 number of CHAR16 characters that were copied into the OutputString buffer.
1196 InputString - String description for this option.
1197 LineWidth - Width of the desired string to extract in CHAR16 characters
1198 Index - Where in InputString to start the copy process
1199 OutputString - Buffer to copy the string into
1202 Returns the number of CHAR16 characters that were copied into the OutputString buffer.
1207 static BOOLEAN Finished
;
1219 *OutputString
= AllocateZeroPool (((UINTN
) (LineWidth
+ 1) * 2));
1222 // Ensure we have got a valid buffer
1224 if (*OutputString
!= NULL
) {
1226 // Fast-forward the string and see if there is a carriage-return in the string
1228 for (; (InputString
[*Index
+ Count2
] != CHAR_CARRIAGE_RETURN
) && (Count2
!= LineWidth
); Count2
++)
1232 // Copy the desired LineWidth of data to the output buffer.
1233 // Also make sure that we don't copy more than the string.
1234 // Also make sure that if there are linefeeds, we account for them.
1236 if ((StrSize (&InputString
[*Index
]) <= ((UINTN
) (LineWidth
+ 1) * 2)) &&
1237 (StrSize (&InputString
[*Index
]) <= ((UINTN
) (Count2
+ 1) * 2))
1240 // Convert to CHAR16 value and show that we are done with this operation
1242 LineWidth
= (UINT16
) ((StrSize (&InputString
[*Index
]) - 2) / 2);
1243 if (LineWidth
!= 0) {
1247 if (Count2
== LineWidth
) {
1249 // Rewind the string from the maximum size until we see a space to break the line
1251 for (; (InputString
[*Index
+ LineWidth
] != CHAR_SPACE
) && (LineWidth
!= 0); LineWidth
--)
1253 if (LineWidth
== 0) {
1261 CopyMem (*OutputString
, &InputString
[*Index
], LineWidth
* 2);
1264 // If currently pointing to a space, increment the index to the first non-space character
1267 (InputString
[*Index
+ LineWidth
] == CHAR_SPACE
) || (InputString
[*Index
+ LineWidth
] == CHAR_CARRIAGE_RETURN
);
1271 *Index
= (UINT16
) (*Index
+ LineWidth
);
1279 UpdateOptionSkipLines (
1280 IN EFI_IFR_DATA_ARRAY
*PageData
,
1281 IN UI_MENU_OPTION
*MenuOption
,
1282 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
1283 IN CHAR16
**OptionalString
,
1292 CHAR16
*OutputString
;
1293 CHAR16
*OptionString
;
1296 OptionString
= *OptionalString
;
1297 OutputString
= NULL
;
1299 ProcessOptions (MenuOption
, FALSE
, FileFormTagsHead
, PageData
, &OptionString
);
1301 if (OptionString
!= NULL
) {
1303 // If leading spaces on OptionString - remove the spaces
1305 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
1308 for (Loop
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1309 OptionString
[Loop
] = OptionString
[Index
];
1313 OptionString
[Loop
] = CHAR_NULL
;
1315 Width
= (UINT16
) gOptionBlockWidth
;
1319 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1321 // If there is more string to process print on the next row and increment the Skip value
1323 if (StrLen (&OptionString
[Index
])) {
1324 if (SkipValue
== 0) {
1327 // Since the Number of lines for this menu entry may or may not be reflected accurately
1328 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1329 // some testing to ensure we are keeping this in-sync.
1331 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1333 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1339 gBS
->FreePool (OutputString
);
1340 if (SkipValue
!= 0) {
1348 *OptionalString
= OptionString
;
1351 // Search table for UiDisplayMenu()
1353 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation
[] = {
1355 { SCAN_DOWN
, UiDown
},
1356 { SCAN_PAGE_UP
, UiPageUp
},
1357 { SCAN_PAGE_DOWN
, UiPageDown
},
1358 { SCAN_ESC
, UiReset
},
1359 { SCAN_F2
, UiPrevious
},
1360 { SCAN_LEFT
, UiLeft
},
1361 { SCAN_RIGHT
, UiRight
},
1362 { SCAN_F9
, UiDefault
},
1363 { SCAN_F10
, UiSave
}
1366 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag
[] = {
1367 { UiNoOperation
, CfUiNoOperation
},
1368 { UiDefault
, CfUiDefault
},
1369 { UiSelect
, CfUiSelect
},
1371 { UiDown
, CfUiDown
},
1372 { UiLeft
, CfUiLeft
},
1373 { UiRight
, CfUiRight
},
1374 { UiReset
, CfUiReset
},
1375 { UiSave
, CfUiSave
},
1376 { UiPrevious
, CfUiPrevious
},
1377 { UiPageUp
, CfUiPageUp
},
1378 { UiPageDown
, CfUiPageDown
}
1384 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
1385 OUT EFI_IFR_DATA_ARRAY
*PageData
1389 Routine Description:
1390 Display menu and wait for user to select one menu option, then return it.
1391 If AutoBoot is enabled, then if user doesn't select any option,
1392 after period of time, it will automatically return the first menu option.
1395 SubMenu - Indicate is sub menu.
1396 FileFormTagsHead - A pointer to the EFI_FILE_FORM_TAGS structure.
1397 PageData - A pointer to the EFI_IFR_DATA_ARRAY.
1400 Return the pointer of the menu which selected,
1401 otherwise return NULL.
1416 UINTN DataAndTimeLineNumberPad
;
1418 INT16 OriginalTimeOut
;
1422 CHAR16
*OptionString
;
1423 CHAR16
*OutputString
;
1424 CHAR16
*FormattedString
;
1431 UI_MENU_LIST
*UiMenuList
;
1435 LIST_ENTRY
*TopOfScreen
;
1436 LIST_ENTRY
*SavedListEntry
;
1437 UI_MENU_OPTION
*Selection
;
1438 UI_MENU_OPTION
*MenuOption
;
1439 UI_MENU_OPTION
*NextMenuOption
;
1440 UI_MENU_OPTION
*SavedMenuOption
;
1441 UI_MENU_OPTION
*PreviousMenuOption
;
1442 EFI_IFR_BINARY
*IfrBinary
;
1443 UI_CONTROL_FLAG ControlFlag
;
1444 EFI_SCREEN_DESCRIPTOR LocalScreen
;
1445 EFI_FILE_FORM_TAGS
*FileFormTags
;
1446 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
1447 MENU_REFRESH_ENTRY
*OldMenuRefreshEntry
;
1448 UI_SCREEN_OPERATION ScreenOperation
;
1449 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
1450 EFI_FORM_CALLBACK_PROTOCOL
*FormCallback
;
1451 EFI_HII_VARIABLE_PACK_LIST
*NvMapListHead
;
1452 EFI_HII_VARIABLE_PACK_LIST
*NvMapListNode
;
1456 CopyMem (&LocalScreen
, &gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
1458 VariableDefinition
= NULL
;
1459 Status
= EFI_SUCCESS
;
1460 FormattedString
= NULL
;
1461 OptionString
= NULL
;
1462 ScreenOperation
= UiNoOperation
;
1464 FormCallback
= NULL
;
1465 FileFormTags
= NULL
;
1466 OutputString
= NULL
;
1471 MenuRefreshEntry
= gMenuRefreshHead
;
1472 OldMenuRefreshEntry
= gMenuRefreshHead
;
1473 NextMenuOption
= NULL
;
1474 PreviousMenuOption
= NULL
;
1475 SavedMenuOption
= NULL
;
1480 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
1482 if (gClassOfVfr
== EFI_FRONT_PAGE_SUBCLASS
) {
1483 TopRow
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1484 Row
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1486 TopRow
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1487 Row
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1491 Col
= LocalScreen
.LeftColumn
;
1493 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
1496 BottomRow
= LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
- SCROLL_ARROW_HEIGHT
- 1;
1498 TopOfScreen
= Menu
.ForwardLink
;
1503 // Get user's selection
1506 NewPos
= Menu
.ForwardLink
;
1507 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
1509 UpdateStatusBar (REFRESH_STATUS_BAR
, (UINT8
) 0, TRUE
);
1511 ControlFlag
= CfInitialization
;
1514 switch (ControlFlag
) {
1515 case CfInitialization
:
1516 ControlFlag
= CfCheckSelection
;
1517 if (gExitRequired
) {
1518 ScreenOperation
= UiReset
;
1519 ControlFlag
= CfScreenOperation
;
1520 } else if (gSaveRequired
) {
1521 ScreenOperation
= UiSave
;
1522 ControlFlag
= CfScreenOperation
;
1523 } else if (IsListEmpty (&Menu
)) {
1524 ControlFlag
= CfReadKey
;
1528 case CfCheckSelection
:
1529 if (Selection
!= NULL
) {
1530 ControlFlag
= CfExit
;
1532 ControlFlag
= CfRepaint
;
1535 FileFormTags
= FileFormTagsHead
;
1539 ControlFlag
= CfRefreshHighLight
;
1545 SavedMenuOption
= MenuOption
;
1554 LocalScreen
.LeftColumn
,
1555 LocalScreen
.RightColumn
,
1556 TopRow
- SCROLL_ARROW_HEIGHT
,
1557 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1558 FIELD_TEXT
| FIELD_BACKGROUND
1561 while (gMenuRefreshHead
!= NULL
) {
1562 OldMenuRefreshEntry
= gMenuRefreshHead
->Next
;
1564 gBS
->FreePool (gMenuRefreshHead
);
1566 gMenuRefreshHead
= OldMenuRefreshEntry
;
1569 for (Link
= TopOfScreen
; Link
!= &Menu
; Link
= Link
->ForwardLink
) {
1570 MenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
1571 MenuOption
->Row
= Row
;
1573 MenuOption
->Col
= Col
;
1574 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
1577 if (MenuOption
->ThisTag
->GrayOut
) {
1578 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
1580 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
1581 gST
->ConOut
->SetAttribute (gST
->ConOut
, SUBTITLE_TEXT
| FIELD_BACKGROUND
);
1585 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
1589 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
1590 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1591 PrintStringAt (Col
, Row
, OutputString
);
1594 // If there is more string to process print on the next row and increment the Skip value
1596 if (StrLen (&MenuOption
->Description
[Index
])) {
1602 gBS
->FreePool (OutputString
);
1612 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1613 ProcessOptions (MenuOption
, FALSE
, FileFormTagsHead
, PageData
, &OptionString
);
1615 if (OptionString
!= NULL
) {
1617 // If leading spaces on OptionString - remove the spaces
1619 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
1620 MenuOption
->OptCol
++;
1623 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1624 OptionString
[Count
] = OptionString
[Index
];
1628 OptionString
[Count
] = CHAR_NULL
;
1631 // If this is a date or time op-code and is used to reflect an RTC, register the op-code
1633 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
1634 MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
) &&
1635 (MenuOption
->ThisTag
->StorageStart
>= FileFormTags
->FormTags
.Tags
[0].NvDataSize
)) {
1637 if (gMenuRefreshHead
== NULL
) {
1638 MenuRefreshEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1639 ASSERT (MenuRefreshEntry
!= NULL
);
1640 MenuRefreshEntry
->MenuOption
= MenuOption
;
1641 MenuRefreshEntry
->FileFormTagsHead
= FileFormTagsHead
;
1642 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1643 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1644 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT
| FIELD_BACKGROUND
;
1645 gMenuRefreshHead
= MenuRefreshEntry
;
1648 // Advance to the last entry
1650 for (MenuRefreshEntry
= gMenuRefreshHead
;
1651 MenuRefreshEntry
->Next
!= NULL
;
1652 MenuRefreshEntry
= MenuRefreshEntry
->Next
1655 MenuRefreshEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1656 ASSERT (MenuRefreshEntry
->Next
!= NULL
);
1657 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
1658 MenuRefreshEntry
->MenuOption
= MenuOption
;
1659 MenuRefreshEntry
->FileFormTagsHead
= FileFormTagsHead
;
1660 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1661 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1662 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT
| FIELD_BACKGROUND
;
1666 Width
= (UINT16
) gOptionBlockWidth
;
1670 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1671 if ((Temp2
== 0) && (Row
<= BottomRow
)) {
1672 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1675 // If there is more string to process print on the next row and increment the Skip value
1677 if (StrLen (&OptionString
[Index
])) {
1681 // Since the Number of lines for this menu entry may or may not be reflected accurately
1682 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1683 // some testing to ensure we are keeping this in-sync.
1685 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1687 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1693 gBS
->FreePool (OutputString
);
1703 // If this is a text op with secondary text information
1705 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_TEXT_OP
) && (MenuOption
->ThisTag
->TextTwo
!= 0)) {
1706 StringPtr
= GetToken (MenuOption
->ThisTag
->TextTwo
, MenuOption
->Handle
);
1708 Width
= (UINT16
) gOptionBlockWidth
;
1712 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &Index
, &OutputString
) != 0x0000;) {
1713 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1714 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1717 // If there is more string to process print on the next row and increment the Skip value
1719 if (StrLen (&StringPtr
[Index
])) {
1723 // Since the Number of lines for this menu entry may or may not be reflected accurately
1724 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1725 // some testing to ensure we are keeping this in-sync.
1727 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1729 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1735 gBS
->FreePool (OutputString
);
1742 gBS
->FreePool (StringPtr
);
1746 // For now, assume left-justified 72 width max setup entries
1748 PrintStringAt (Col
, Row
, MenuOption
->Description
);
1751 // Tracker 6210 - need to handle the bottom of the display
1753 if (MenuOption
->Skip
> 1) {
1754 Row
+= MenuOption
->Skip
- SkipValue
;
1757 Row
+= MenuOption
->Skip
;
1760 if (Row
> BottomRow
) {
1761 if (!ValueIsScroll (FALSE
, Link
)) {
1765 Row
= BottomRow
+ 1;
1770 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
1775 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
1777 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
1778 TopRow
- SCROLL_ARROW_HEIGHT
,
1782 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1786 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
1788 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
1789 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1793 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1796 if (SavedMenuOption
!= NULL
) {
1797 MenuOption
= SavedMenuOption
;
1802 case CfRefreshHighLight
:
1803 ControlFlag
= CfUpdateHelpString
;
1805 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily
1806 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.
1808 SavedValue
= Repaint
;
1811 if (NewPos
!= NULL
) {
1812 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
1814 if (gLastOpr
&& (gEntryNumber
!= -1)) {
1815 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
1816 if (gEntryNumber
!= MenuOption
->EntryNumber
) {
1817 ScreenOperation
= UiDown
;
1818 ControlFlag
= CfScreenOperation
;
1825 ProcessOptions (MenuOption
, FALSE
, FileFormTagsHead
, PageData
, &OptionString
);
1826 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1827 if (OptionString
!= NULL
) {
1829 // If leading spaces on OptionString - remove the spaces
1831 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
1834 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1835 OptionString
[Count
] = OptionString
[Index
];
1839 OptionString
[Count
] = CHAR_NULL
;
1841 Width
= (UINT16
) gOptionBlockWidth
;
1843 OriginalRow
= MenuOption
->Row
;
1845 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1846 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
1847 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
1850 // If there is more string to process print on the next row and increment the Skip value
1852 if (StrLen (&OptionString
[Index
])) {
1856 gBS
->FreePool (OutputString
);
1859 MenuOption
->Row
= OriginalRow
;
1862 if (MenuOption
->ThisTag
->GrayOut
) {
1863 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
1865 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
1866 gST
->ConOut
->SetAttribute (gST
->ConOut
, SUBTITLE_TEXT
| FIELD_BACKGROUND
);
1870 OriginalRow
= MenuOption
->Row
;
1871 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
1873 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
1874 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
1875 PrintStringAt (Col
, MenuOption
->Row
, OutputString
);
1878 // If there is more string to process print on the next row and increment the Skip value
1880 if (StrLen (&MenuOption
->Description
[Index
])) {
1884 gBS
->FreePool (OutputString
);
1887 MenuOption
->Row
= OriginalRow
;
1888 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1892 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1893 gST
->ConOut
->OutputString (gST
->ConOut
, MenuOption
->Description
);
1896 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
1898 if ((gPriorMenuEntry
!= 0) && (MenuOption
->EntryNumber
!= gPriorMenuEntry
) && (NewPos
->ForwardLink
!= &Menu
)) {
1899 ScreenOperation
= UiDown
;
1900 ControlFlag
= CfScreenOperation
;
1903 gPriorMenuEntry
= 0;
1906 // This is only possible if we entered this page and the first menu option is
1907 // a "non-menu" item. In that case, force it UiDown
1909 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| MenuOption
->ThisTag
->GrayOut
) {
1911 // If we previously hit an UP command and we are still sitting on a text operation
1912 // we must continue going up
1914 if (ScreenOperation
== UiUp
) {
1915 ControlFlag
= CfScreenOperation
;
1918 ScreenOperation
= UiDown
;
1919 ControlFlag
= CfScreenOperation
;
1924 // Set reverse attribute
1926 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
| FIELD_BACKGROUND_HIGHLIGHT
);
1927 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
1930 // Assuming that we have a refresh linked-list created, lets annotate the
1931 // appropriate entry that we are highlighting with its new attribute. Just prior to this
1932 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh
1934 if (gMenuRefreshHead
!= NULL
) {
1935 for (MenuRefreshEntry
= gMenuRefreshHead
; MenuRefreshEntry
!= NULL
; MenuRefreshEntry
= MenuRefreshEntry
->Next
) {
1936 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT
| FIELD_BACKGROUND
;
1937 if (MenuRefreshEntry
->MenuOption
== MenuOption
) {
1938 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_HIGHLIGHT
| FIELD_BACKGROUND_HIGHLIGHT
;
1944 ProcessOptions (MenuOption
, FALSE
, FileFormTagsHead
, PageData
, &OptionString
);
1945 if (OptionString
!= NULL
) {
1947 // If leading spaces on OptionString - remove the spaces
1949 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
1952 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1953 OptionString
[Count
] = OptionString
[Index
];
1957 OptionString
[Count
] = CHAR_NULL
;
1959 Width
= (UINT16
) gOptionBlockWidth
;
1961 OriginalRow
= MenuOption
->Row
;
1963 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1964 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
1965 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
1968 // If there is more string to process print on the next row and increment the Skip value
1970 if (StrLen (&OptionString
[Index
])) {
1974 gBS
->FreePool (OutputString
);
1977 MenuOption
->Row
= OriginalRow
;
1980 OriginalRow
= MenuOption
->Row
;
1982 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
1984 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
1985 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
1986 PrintStringAt (Col
, MenuOption
->Row
, OutputString
);
1989 // If there is more string to process print on the next row and increment the Skip value
1991 if (StrLen (&MenuOption
->Description
[Index
])) {
1995 gBS
->FreePool (OutputString
);
1998 MenuOption
->Row
= OriginalRow
;
2003 if (((NewPos
->ForwardLink
!= &Menu
) && (ScreenOperation
== UiDown
)) ||
2004 ((NewPos
->BackLink
!= &Menu
) && (ScreenOperation
== UiUp
)) ||
2005 (ScreenOperation
== UiNoOperation
)
2007 UpdateKeyHelp (MenuOption
, FALSE
);
2010 gST
->ConOut
->OutputString (gST
->ConOut
, MenuOption
->Description
);
2013 // Clear reverse attribute
2015 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
2018 // Repaint flag will be used when process CfUpdateHelpString, so restore its value
2019 // if we didn't break halfway when process CfRefreshHighLight.
2021 Repaint
= SavedValue
;
2024 case CfUpdateHelpString
:
2025 ControlFlag
= CfPrepareToReadKey
;
2028 (Repaint
|| NewLine
||
2029 (MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2030 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) &&
2031 !(gClassOfVfr
== EFI_GENERAL_APPLICATION_SUBCLASS
)) {
2033 // Don't print anything if it is a NULL help token
2035 if (MenuOption
->ThisTag
->Help
== 0x00000000) {
2036 StringPtr
= (CHAR16
*) L
"\0";
2038 StringPtr
= GetToken (MenuOption
->ThisTag
->Help
, MenuOption
->Handle
);
2041 ProcessHelpString (StringPtr
, &FormattedString
, BottomRow
- TopRow
);
2043 gST
->ConOut
->SetAttribute (gST
->ConOut
, HELP_TEXT
| FIELD_BACKGROUND
);
2045 for (Index
= 0; Index
< BottomRow
- TopRow
; Index
++) {
2047 // Pad String with spaces to simulate a clearing of the previous line
2049 for (; GetStringWidth (&FormattedString
[Index
* gHelpBlockWidth
]) / 2 < gHelpBlockWidth
;) {
2050 StrCat (&FormattedString
[Index
* gHelpBlockWidth
], (CHAR16
*) L
" ");
2054 LocalScreen
.RightColumn
- gHelpBlockWidth
,
2056 &FormattedString
[Index
* gHelpBlockWidth
]
2061 // Reset this flag every time we finish using it.
2067 case CfPrepareToReadKey
:
2068 ControlFlag
= CfReadKey
;
2070 for (Index
= 0; Index
< MenuOption
->IfrNumber
; Index
++) {
2071 FileFormTags
= FileFormTags
->NextFile
;
2074 ScreenOperation
= UiNoOperation
;
2076 Status
= gBS
->HandleProtocol (
2077 (VOID
*) (UINTN
) FileFormTags
->FormTags
.Tags
[0].CallbackHandle
,
2078 &gEfiFormCallbackProtocolGuid
,
2079 (VOID
**) &FormCallback
2085 ControlFlag
= CfScreenOperation
;
2087 OriginalTimeOut
= FrontPageTimeOutValue
;
2089 if (FrontPageTimeOutValue
>= 0 && (gClassOfVfr
== EFI_FRONT_PAGE_SUBCLASS
) && FrontPageTimeOutValue
!= (INT16
) -1) {
2091 // Remember that if set to 0, must immediately boot an option
2093 if (FrontPageTimeOutValue
== 0) {
2094 FrontPageTimeOutValue
= 0xFFFF;
2095 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2096 if (EFI_ERROR (Status
)) {
2097 Status
= EFI_TIMEOUT
;
2102 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, ONE_SECOND
);
2103 if (Status
== EFI_TIMEOUT
) {
2104 EFI_IFR_DATA_ENTRY
*DataEntry
;
2106 DataEntry
= (EFI_IFR_DATA_ENTRY
*) (PageData
+ 1);
2108 PageData
->EntryCount
= 1;
2109 Count
= (UINT32
) ((OriginalTimeOut
- FrontPageTimeOutValue
) * 100 / OriginalTimeOut
);
2110 CopyMem (&DataEntry
->Data
, &Count
, sizeof (UINT32
));
2112 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
2113 FormCallback
->Callback (
2116 (EFI_IFR_DATA_ARRAY
*) PageData
,
2121 // Count down 1 second
2123 FrontPageTimeOutValue
--;
2126 ASSERT (!EFI_ERROR (Status
));
2127 PageData
->EntryCount
= 0;
2128 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
2129 FormCallback
->Callback (
2132 (EFI_IFR_DATA_ARRAY
*) PageData
,
2137 FrontPageTimeOutValue
= 0xFFFF;
2141 // Wait for user's selection, no auto boot
2143 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0);
2145 } while (Status
== EFI_TIMEOUT
);
2149 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
2150 DisableQuietBoot ();
2153 if (Status
== EFI_TIMEOUT
) {
2154 Key
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
2156 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2158 // if we encounter error, continue to read another key in.
2160 if (EFI_ERROR (Status
)) {
2161 ControlFlag
= CfReadKey
;
2166 switch (Key
.UnicodeChar
) {
2167 case CHAR_CARRIAGE_RETURN
:
2168 Selection
= MenuOption
;
2169 ScreenOperation
= UiSelect
;
2174 // We will push the adjustment of these numeric values directly to the input handler
2178 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2180 if (Key
.UnicodeChar
== '+') {
2181 gDirection
= SCAN_RIGHT
;
2183 gDirection
= SCAN_LEFT
;
2186 Status
= ProcessOptions (MenuOption
, TRUE
, FileFormTagsHead
, NULL
, &OptionString
);
2191 ScreenOperation
= UiUp
;
2196 ScreenOperation
= UiDown
;
2200 if (gClassOfVfr
!= EFI_FRONT_PAGE_SUBCLASS
) {
2202 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_CHECKBOX_OP
&& !(MenuOption
->ThisTag
->GrayOut
)) {
2203 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2204 gST
->ConOut
->OutputString (gST
->ConOut
, MenuOption
->Description
);
2205 Selection
= MenuOption
;
2206 ScreenOperation
= UiSelect
;
2213 if (((Key
.ScanCode
== SCAN_F1
) && ((gFunctionKeySetting
& FUNCTION_ONE
) != FUNCTION_ONE
)) ||
2214 ((Key
.ScanCode
== SCAN_F2
) && ((gFunctionKeySetting
& FUNCTION_TWO
) != FUNCTION_TWO
)) ||
2215 ((Key
.ScanCode
== SCAN_F9
) && ((gFunctionKeySetting
& FUNCTION_NINE
) != FUNCTION_NINE
)) ||
2216 ((Key
.ScanCode
== SCAN_F10
) && ((gFunctionKeySetting
& FUNCTION_TEN
) != FUNCTION_TEN
))
2219 // If the function key has been disabled, just ignore the key.
2222 for (Index
= 0; Index
< sizeof (gScanCodeToOperation
) / sizeof (gScanCodeToOperation
[0]); Index
++) {
2223 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
2224 if ((Key
.ScanCode
== SCAN_F9
) || (Key
.ScanCode
== SCAN_F10
)) {
2226 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2229 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2238 case CfScreenOperation
:
2239 IfrBinary
= gBinaryDataHead
;
2242 // Advance to the Ifr we are using
2244 for (Index
= 0; Index
< gActiveIfr
; Index
++) {
2245 IfrBinary
= IfrBinary
->Next
;
2248 if (ScreenOperation
!= UiPrevious
&& ScreenOperation
!= UiReset
) {
2250 // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset
2251 // ignore the selection and go back to reading keys.
2253 if (IsListEmpty (&Menu
)) {
2254 ControlFlag
= CfReadKey
;
2258 // if there is nothing logical to place a cursor on, just move on to wait for a key.
2260 for (Link
= Menu
.ForwardLink
; Link
!= &Menu
; Link
= Link
->ForwardLink
) {
2261 NextMenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2262 if (!(NextMenuOption
->ThisTag
->GrayOut
) && (NextMenuOption
->ThisTag
->Operand
!= EFI_IFR_SUBTITLE_OP
)) {
2267 if (Link
== &Menu
) {
2268 ControlFlag
= CfPrepareToReadKey
;
2274 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
2277 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
2278 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
2285 ControlFlag
= CfCheckSelection
;
2287 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2289 if (MenuOption
!= NULL
) {
2290 if (!SelectionsAreValid (MenuOption
, FileFormTagsHead
)) {
2297 if (IsListEmpty (&gMenuList
)) {
2299 if (IsListEmpty (&Menu
)) {
2300 ControlFlag
= CfReadKey
;
2307 while (gMenuRefreshHead
!= NULL
) {
2308 OldMenuRefreshEntry
= gMenuRefreshHead
->Next
;
2310 gBS
->FreePool (gMenuRefreshHead
);
2312 gMenuRefreshHead
= OldMenuRefreshEntry
;
2315 // Remove the Cached page entry, free and init the menus, flag Selection as jumping to previous page and a valid Tag
2318 UiRemoveMenuListEntry (MenuOption
, &Selection
);
2319 Selection
->Previous
= TRUE
;
2324 gActiveIfr
= Selection
->IfrNumber
;
2328 ControlFlag
= CfCheckSelection
;
2330 ExtractRequestedNvMap (FileFormTags
, MenuOption
->ThisTag
->VariableNumber
, &VariableDefinition
);
2333 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_TEXT_OP
&&
2334 !(MenuOption
->ThisTag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
)) ||
2335 (MenuOption
->ThisTag
->GrayOut
) ||
2336 (MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2337 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2343 UpdateKeyHelp (MenuOption
, TRUE
);
2344 Status
= ProcessOptions (MenuOption
, TRUE
, FileFormTagsHead
, PageData
, &OptionString
);
2346 if (EFI_ERROR (Status
)) {
2352 if (OptionString
!= NULL
) {
2353 PrintStringAt (LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ 1, MenuOption
->Row
, OptionString
);
2356 if (MenuOption
->ThisTag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
2357 Selection
= MenuOption
;
2360 if (Selection
== NULL
) {
2364 Location
= (UINT8
*) &PageData
->EntryCount
;
2367 // If not a goto, dump single piece of data, otherwise dump everything
2369 if (Selection
->ThisTag
->Operand
== EFI_IFR_REF_OP
) {
2371 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2373 if (!SelectionsAreValid (MenuOption
, FileFormTagsHead
)) {
2379 UiAddMenuListEntry (Selection
);
2380 gPriorMenuEntry
= 0;
2383 // Now that we added a menu entry specific to a goto, we can always go back when someone hits the UiPrevious
2385 UiMenuList
= CR (gMenuList
.ForwardLink
, UI_MENU_LIST
, MenuLink
, UI_MENU_LIST_SIGNATURE
);
2386 UiMenuList
->FormerEntryNumber
= MenuOption
->EntryNumber
;
2391 // Rewind to the beginning of the menu
2393 for (; NewPos
->BackLink
!= &Menu
; NewPos
= NewPos
->BackLink
)
2397 // Get Total Count of Menu entries
2399 for (Count
= 1; NewPos
->ForwardLink
!= &Menu
; NewPos
= NewPos
->ForwardLink
) {
2403 // Rewind to the beginning of the menu
2405 for (; NewPos
->BackLink
!= &Menu
; NewPos
= NewPos
->BackLink
)
2409 // Copy the number of entries being described to the PageData location
2411 CopyMem (&Location
[0], &Count
, sizeof (UINT32
));
2413 for (Index
= 4; NewPos
->ForwardLink
!= &Menu
; Index
= Index
+ MenuOption
->ThisTag
->StorageWidth
+ 2) {
2415 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2416 Location
[Index
] = MenuOption
->ThisTag
->Operand
;
2417 Location
[Index
+ 1] = (UINT8
) (MenuOption
->ThisTag
->StorageWidth
+ 4);
2419 &Location
[Index
+ 4],
2420 &VariableDefinition
->NvRamMap
[MenuOption
->ThisTag
->StorageStart
],
2421 MenuOption
->ThisTag
->StorageWidth
2423 NewPos
= NewPos
->ForwardLink
;
2427 gPriorMenuEntry
= MenuOption
->EntryNumber
;
2432 // Copy the number of entries being described to the PageData location
2434 CopyMem (&Location
[0], &Count
, sizeof (UINT32
));
2437 // Start at PageData[4] since the EntryCount is a UINT32
2442 // Copy data to destination
2444 Location
[Index
] = MenuOption
->ThisTag
->Operand
;
2445 Location
[Index
+ 1] = (UINT8
) (MenuOption
->ThisTag
->StorageWidth
+ 4);
2447 &Location
[Index
+ 4],
2448 &VariableDefinition
->NvRamMap
[MenuOption
->ThisTag
->StorageStart
],
2449 MenuOption
->ThisTag
->StorageWidth
2456 ControlFlag
= CfCheckSelection
;
2458 if (gClassOfVfr
== EFI_FRONT_PAGE_SUBCLASS
) {
2462 // If NV flag is up, prompt user
2464 if (gNvUpdateRequired
) {
2465 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2467 YesResponse
= gYesResponse
[0];
2468 NoResponse
= gNoResponse
[0];
2471 CreateDialog (3, TRUE
, 0, NULL
, &Key
, gEmptyString
, gAreYouSure
, gEmptyString
);
2474 (Key
.ScanCode
!= SCAN_ESC
) &&
2475 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (NoResponse
| UPPER_LOWER_CASE_OFFSET
)) &&
2476 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (YesResponse
| UPPER_LOWER_CASE_OFFSET
))
2480 // If the user hits the YesResponse key
2482 if ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) == (YesResponse
| UPPER_LOWER_CASE_OFFSET
)) {
2490 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2492 if (MenuOption
!= NULL
) {
2493 if (!SelectionsAreValid (MenuOption
, FileFormTagsHead
)) {
2501 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
2502 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
2506 gST
->ConOut
->ClearScreen (gST
->ConOut
);
2510 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->Flags
, FALSE
);
2511 UpdateStatusBar (NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->Flags
, FALSE
);
2513 if (IfrBinary
->UnRegisterOnExit
) {
2514 Hii
->RemovePack (Hii
, MenuOption
->Handle
);
2520 // Clean up the allocated data buffers
2522 FreeData (FileFormTagsHead
, FormattedString
, OptionString
);
2524 gST
->ConOut
->ClearScreen (gST
->ConOut
);
2528 ControlFlag
= CfCheckSelection
;
2529 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2530 if (MenuOption
->Skip
== 1) {
2532 // In the tail of the Date/Time op-code set, go left.
2534 NewPos
= NewPos
->BackLink
;
2537 // In the middle of the Data/Time op-code set, go left.
2539 NextMenuOption
= CR (NewPos
->ForwardLink
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2540 if (NextMenuOption
->Skip
== 1) {
2541 NewPos
= NewPos
->BackLink
;
2548 ControlFlag
= CfCheckSelection
;
2549 if ((MenuOption
->Skip
== 0) &&
2550 ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
))
2553 // We are in the head or middle of the Date/Time op-code set, advance right.
2555 NewPos
= NewPos
->ForwardLink
;
2560 ControlFlag
= CfCheckSelection
;
2562 if (NewPos
->BackLink
!= &Menu
) {
2565 // Adjust Date/Time position before we advance forward.
2567 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2570 // Caution that we have already rewind to the top, don't go backward in this situation.
2572 if (NewPos
->BackLink
!= &Menu
) {
2573 NewPos
= NewPos
->BackLink
;
2576 PreviousMenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2579 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended
2580 // to be one that back to the previous set of op-codes, we need to advance to the sencond
2581 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
2582 // checking can be done.
2584 DataAndTimeLineNumberPad
= AdjustDateAndTimePosition (TRUE
, &NewPos
);
2588 // If the previous MenuOption contains a display-only op-code, skip to the next one
2590 if (PreviousMenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| PreviousMenuOption
->ThisTag
->GrayOut
) {
2592 // This is ok as long as not at the end of the list
2594 if (NewPos
->BackLink
== &Menu
) {
2596 // If we are at the start of the list, then this list must start with a display only
2597 // piece of data, so do not allow the backward motion
2599 ScreenOperation
= UiDown
;
2601 if (PreviousMenuOption
->Row
<= TopRow
) {
2602 if (TopOfScreen
->BackLink
!= &Menu
) {
2603 TopOfScreen
= TopOfScreen
->BackLink
;
2608 UpdateStatusBar (INPUT_ERROR
, PreviousMenuOption
->ThisTag
->Flags
, FALSE
);
2614 // Check the previous menu entry to see if it was a zero-length advance. If it was,
2615 // don't worry about a redraw.
2617 if ((MenuOption
->Row
- PreviousMenuOption
->Skip
- DataAndTimeLineNumberPad
< TopRow
) ||
2618 (PreviousMenuOption
->Skip
> MenuOption
->Row
)
2621 if (TopOfScreen
->BackLink
== &Menu
) {
2628 // Is the current top of screen a zero-advance op-code?
2629 // If so, keep moving forward till we hit a >0 advance op-code
2631 SavedMenuOption
= CR (TopOfScreen
->BackLink
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2632 TopOfScreen
= TopOfScreen
->BackLink
;
2633 } while (SavedMenuOption
->Skip
== 0);
2635 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2637 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2640 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->Flags
, FALSE
);
2643 SavedMenuOption
= MenuOption
;
2644 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2645 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| MenuOption
->ThisTag
->GrayOut
) {
2647 // If we are at the end of the list and sitting on a text op, we need to more forward
2649 ScreenOperation
= UiDown
;
2650 ControlFlag
= CfScreenOperation
;
2654 MenuOption
= SavedMenuOption
;
2660 ControlFlag
= CfCheckSelection
;
2662 SavedListEntry
= NewPos
;
2664 for (Index
= BottomRow
; Index
>= TopRow
+ 1; Index
-= MenuOption
->Skip
) {
2665 if (Link
->BackLink
== &Menu
) {
2667 Link
= SavedListEntry
;
2668 MenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2674 Link
= Link
->BackLink
;
2675 MenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2677 SavedListEntry
= Link
;
2683 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2684 // Don't do this when we are already in the first page.
2687 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2688 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2689 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2694 ControlFlag
= CfCheckSelection
;
2696 SavedListEntry
= NewPos
;
2698 NewPos
= TopOfScreen
;
2699 for (Index
= TopRow
; Index
<= BottomRow
- 1; Index
+= MenuOption
->Skip
) {
2700 if (NewPos
->ForwardLink
== &Menu
) {
2701 NewPos
= SavedListEntry
;
2702 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2711 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2712 NewPos
= NewPos
->ForwardLink
;
2719 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2720 // Don't do this when we are already in the last page.
2723 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2724 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2725 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2730 ControlFlag
= CfCheckSelection
;
2732 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
2733 // to be one that progresses to the next set of op-codes, we need to advance to the last
2734 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
2735 // checking can be done. The only other logic we need to introduce is that if a Date/Time
2736 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
2737 // the Date/Time op-code.
2739 DataAndTimeLineNumberPad
= AdjustDateAndTimePosition (FALSE
, &NewPos
);
2741 if (NewPos
->ForwardLink
!= &Menu
) {
2743 NewPos
= NewPos
->ForwardLink
;
2744 NextMenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2748 // If the next MenuOption contains a display-only op-code, skip to the next one
2749 // Also if the next MenuOption is date or time,
2751 if (NextMenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| NextMenuOption
->ThisTag
->GrayOut
) {
2753 // This is ok as long as not at the end of the list
2755 if (NewPos
== &Menu
) {
2757 // If we are at the end of the list, then this list must end with a display only
2758 // piece of data, so do not allow the forward motion
2760 UpdateStatusBar (INPUT_ERROR
, NextMenuOption
->ThisTag
->Flags
, FALSE
);
2761 NewPos
= NewPos
->BackLink
;
2762 ScreenOperation
= UiUp
;
2768 // An option might be multi-line, so we need to reflect that data in the overall skip value
2770 UpdateOptionSkipLines (PageData
, NextMenuOption
, FileFormTagsHead
, &OptionString
, SkipValue
);
2772 if (NextMenuOption
->Skip
> 1) {
2773 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ NextMenuOption
->Skip
- 1;
2775 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DataAndTimeLineNumberPad
;
2778 // If we are going to scroll
2780 if (Temp
> BottomRow
) {
2783 // Is the current top of screen a zero-advance op-code?
2784 // If so, keep moving forward till we hit a >0 advance op-code
2786 SavedMenuOption
= CR (TopOfScreen
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2789 // If bottom op-code is more than one line or top op-code is more than one line
2791 if ((NextMenuOption
->Skip
> 1) || (MenuOption
->Skip
> 1)) {
2793 // Is the bottom op-code greater than or equal in size to the top op-code?
2795 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- OldSkipValue
)) {
2797 // Skip the top op-code
2799 TopOfScreen
= TopOfScreen
->ForwardLink
;
2800 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- OldSkipValue
);
2802 OldSkipValue
= Difference
;
2804 SavedMenuOption
= CR (TopOfScreen
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2807 // If we have a remainder, skip that many more op-codes until we drain the remainder
2810 Difference
>= (INTN
) SavedMenuOption
->Skip
;
2811 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
2814 // Since the Difference is greater than or equal to this op-code's skip value, skip it
2816 TopOfScreen
= TopOfScreen
->ForwardLink
;
2817 SavedMenuOption
= CR (TopOfScreen
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2818 if (Difference
< (INTN
) SavedMenuOption
->Skip
) {
2819 Difference
= SavedMenuOption
->Skip
- Difference
- 1;
2822 if (Difference
== (INTN
) SavedMenuOption
->Skip
) {
2823 TopOfScreen
= TopOfScreen
->ForwardLink
;
2824 SavedMenuOption
= CR (TopOfScreen
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2825 Difference
= SavedMenuOption
->Skip
- Difference
;
2831 // Since we will act on this op-code in the next routine, and increment the
2832 // SkipValue, set the skips to one less than what is required.
2834 SkipValue
= Difference
- 1;
2838 // Since we will act on this op-code in the next routine, and increment the
2839 // SkipValue, set the skips to one less than what is required.
2841 SkipValue
= OldSkipValue
+ (Temp
- BottomRow
) - 1;
2844 if ((OldSkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
2845 TopOfScreen
= TopOfScreen
->ForwardLink
;
2848 SkipValue
= OldSkipValue
;
2852 // If the op-code at the top of the screen is more than one line, let's not skip it yet
2853 // Let's set a skip flag to smoothly scroll the top of the screen.
2855 if (SavedMenuOption
->Skip
> 1) {
2856 if (SavedMenuOption
== NextMenuOption
) {
2863 TopOfScreen
= TopOfScreen
->ForwardLink
;
2865 } while (SavedMenuOption
->Skip
== 0);
2868 OldSkipValue
= SkipValue
;
2871 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->Flags
, FALSE
);
2875 SavedMenuOption
= MenuOption
;
2876 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2877 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| MenuOption
->ThisTag
->GrayOut
) {
2879 // If we are at the end of the list and sitting on a text op, we need to more forward
2881 ScreenOperation
= UiUp
;
2882 ControlFlag
= CfScreenOperation
;
2886 MenuOption
= SavedMenuOption
;
2888 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
2890 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2896 ControlFlag
= CfCheckSelection
;
2898 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2900 if (MenuOption
!= NULL
) {
2901 if (!SelectionsAreValid (MenuOption
, FileFormTagsHead
)) {
2908 // If callbacks are active, and the callback has a Write method, try to use it
2910 if (FileFormTags
->VariableDefinitions
->VariableName
== NULL
) {
2911 if ((FormCallback
!= NULL
) && (FormCallback
->NvWrite
!= NULL
)) {
2912 Status
= FormCallback
->NvWrite (
2914 (CHAR16
*) L
"Setup",
2915 &FileFormTags
->FormTags
.Tags
[0].GuidValue
,
2916 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2917 VariableDefinition
->VariableSize
,
2918 (VOID
*) VariableDefinition
->NvRamMap
,
2923 Status
= gRT
->SetVariable (
2924 (CHAR16
*) L
"Setup",
2925 &FileFormTags
->FormTags
.Tags
[0].GuidValue
,
2926 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2927 VariableDefinition
->VariableSize
,
2928 (VOID
*) VariableDefinition
->NvRamMap
2932 VariableDefinition
= FileFormTags
->VariableDefinitions
;
2934 for (; VariableDefinition
!= NULL
; VariableDefinition
= VariableDefinition
->Next
) {
2935 if ((FormCallback
!= NULL
) && (FormCallback
->NvWrite
!= NULL
)) {
2936 Status
= FormCallback
->NvWrite (
2938 VariableDefinition
->VariableName
,
2939 &VariableDefinition
->Guid
,
2940 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2941 VariableDefinition
->VariableSize
,
2942 (VOID
*) VariableDefinition
->NvRamMap
,
2947 Status
= gRT
->SetVariable (
2948 VariableDefinition
->VariableName
,
2949 &VariableDefinition
->Guid
,
2950 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2951 VariableDefinition
->VariableSize
,
2952 (VOID
*) VariableDefinition
->NvRamMap
2958 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->Flags
, FALSE
);
2959 UpdateStatusBar (NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->Flags
, FALSE
);
2963 ControlFlag
= CfCheckSelection
;
2965 NvMapListHead
= NULL
;
2967 Status
= Hii
->GetDefaultImage (Hii
, MenuOption
->Handle
, EFI_IFR_FLAG_DEFAULT
, &NvMapListHead
);
2969 if (!EFI_ERROR (Status
)) {
2970 ASSERT_EFI_ERROR (NULL
!= NvMapListHead
);
2972 NvMapListNode
= NvMapListHead
;
2974 while (NULL
!= NvMapListNode
) {
2975 if (FileFormTags
->VariableDefinitions
->VariableId
== NvMapListNode
->VariablePack
->VariableId
) {
2976 NvMap
= (VOID
*) ((CHAR8
*) NvMapListNode
->VariablePack
+ sizeof (EFI_HII_VARIABLE_PACK
) + NvMapListNode
->VariablePack
->VariableNameLength
);
2977 NvMapSize
= NvMapListNode
->VariablePack
->Header
.Length
- sizeof (EFI_HII_VARIABLE_PACK
) - NvMapListNode
->VariablePack
->VariableNameLength
;
2980 NvMapListNode
= NvMapListNode
->NextVariablePack
;
2984 // Free the buffer that was allocated.
2986 gBS
->FreePool (FileFormTags
->VariableDefinitions
->NvRamMap
);
2987 gBS
->FreePool (FileFormTags
->VariableDefinitions
->FakeNvRamMap
);
2990 // Allocate, copy the NvRamMap.
2992 FileFormTags
->VariableDefinitions
->VariableFakeSize
= (UINT16
) (FileFormTags
->VariableDefinitions
->VariableFakeSize
- FileFormTags
->VariableDefinitions
->VariableSize
);
2993 FileFormTags
->VariableDefinitions
->VariableSize
= (UINT16
) NvMapSize
;
2994 FileFormTags
->VariableDefinitions
->VariableFakeSize
= (UINT16
) (FileFormTags
->VariableDefinitions
->VariableFakeSize
+ FileFormTags
->VariableDefinitions
->VariableSize
);
2996 FileFormTags
->VariableDefinitions
->NvRamMap
= AllocateZeroPool (FileFormTags
->VariableDefinitions
->VariableSize
);
2997 FileFormTags
->VariableDefinitions
->FakeNvRamMap
= AllocateZeroPool (NvMapSize
+ FileFormTags
->VariableDefinitions
->VariableFakeSize
);
2999 CopyMem (FileFormTags
->VariableDefinitions
->NvRamMap
, NvMap
, NvMapSize
);
3000 gBS
->FreePool (NvMapListHead
);
3003 UpdateStatusBar (NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->Flags
, TRUE
);
3006 // After the repaint operation, we should refresh the highlight.