4 Copyright (c) 2006 - 2007, Intel Corporation
5 All rights reserved. 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
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.
16 // Include common header file for this module.
18 #include "CommonHeader.h"
37 Set Buffer to Value for Size bytes.
41 Buffer - Memory to set.
43 Size - Number of bytes to set
45 Value - Value of the set operation.
68 Initialize Menu option list.
76 InitializeListHead (&Menu
);
86 Initialize Menu option list.
94 InitializeListHead (&gMenuList
);
98 UiRemoveMenuListEntry (
99 IN UI_MENU_OPTION
*Selection
,
100 OUT UI_MENU_OPTION
**PreviousSelection
105 Remove Menu option list.
113 UI_MENU_LIST
*UiMenuList
;
115 *PreviousSelection
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
116 ASSERT (*PreviousSelection
!= NULL
);
118 if (!IsListEmpty (&gMenuList
)) {
119 UiMenuList
= CR (gMenuList
.ForwardLink
, UI_MENU_LIST
, MenuLink
, UI_MENU_LIST_SIGNATURE
);
120 (*PreviousSelection
)->IfrNumber
= UiMenuList
->Selection
.IfrNumber
;
121 (*PreviousSelection
)->FormId
= UiMenuList
->Selection
.FormId
;
122 (*PreviousSelection
)->Tags
= UiMenuList
->Selection
.Tags
;
123 (*PreviousSelection
)->ThisTag
= UiMenuList
->Selection
.ThisTag
;
124 (*PreviousSelection
)->Handle
= UiMenuList
->Selection
.Handle
;
125 gEntryNumber
= UiMenuList
->FormerEntryNumber
;
126 RemoveEntryList (&UiMenuList
->MenuLink
);
127 FreePool (UiMenuList
);
138 Free Menu option linked list.
146 UI_MENU_LIST
*UiMenuList
;
148 while (!IsListEmpty (&gMenuList
)) {
149 UiMenuList
= CR (gMenuList
.ForwardLink
, UI_MENU_LIST
, MenuLink
, UI_MENU_LIST_SIGNATURE
);
150 RemoveEntryList (&UiMenuList
->MenuLink
);
151 FreePool (UiMenuList
);
157 IN UI_MENU_OPTION
*Selection
162 Add one menu entry to the linked lst
170 UI_MENU_LIST
*UiMenuList
;
172 UiMenuList
= AllocateZeroPool (sizeof (UI_MENU_LIST
));
173 ASSERT (UiMenuList
!= NULL
);
175 UiMenuList
->Signature
= UI_MENU_LIST_SIGNATURE
;
176 CopyMem (&UiMenuList
->Selection
, Selection
, sizeof (UI_MENU_OPTION
));
178 InsertHeadList (&gMenuList
, &UiMenuList
->MenuLink
);
188 Free Menu option linked list.
196 UI_MENU_OPTION
*MenuOption
;
198 while (!IsListEmpty (&Menu
)) {
199 MenuOption
= CR (Menu
.ForwardLink
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
200 RemoveEntryList (&MenuOption
->Link
);
203 // We allocated space for this description when we did a GetToken, free it here
205 FreePool (MenuOption
->Description
);
206 FreePool (MenuOption
);
218 Refresh screen with current date and/or time based on screen context
226 CHAR16
*OptionString
;
227 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
233 if (gMenuRefreshHead
!= NULL
) {
235 MenuRefreshEntry
= gMenuRefreshHead
;
238 gST
->ConOut
->SetAttribute (gST
->ConOut
, MenuRefreshEntry
->CurrentAttribute
);
239 ProcessOptions (MenuRefreshEntry
->MenuOption
, FALSE
, MenuRefreshEntry
->FileFormTagsHead
, NULL
, &OptionString
);
241 if (OptionString
!= NULL
) {
243 // If leading spaces on OptionString - remove the spaces
245 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
248 for (Loop
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
249 OptionString
[Loop
] = OptionString
[Index
];
253 OptionString
[Loop
] = CHAR_NULL
;
255 PrintStringAt (MenuRefreshEntry
->CurrentColumn
, MenuRefreshEntry
->CurrentRow
, OptionString
);
258 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
260 } while (MenuRefreshEntry
!= NULL
);
263 if (OptionString
!= NULL
) {
264 FreePool (OptionString
);
269 UiWaitForSingleEvent (
271 IN UINT64 Timeout OPTIONAL
276 Wait for a given event to fire, or for an optional timeout to expire.
279 Event - The event to wait for
281 Timeout - An optional timeout value in 100 ns units.
285 EFI_SUCCESS - Event fired before Timeout expired.
286 EFI_TIME_OUT - Timout expired before Event fired.
292 EFI_EVENT TimerEvent
;
293 EFI_EVENT WaitList
[2];
297 // Create a timer event
299 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
300 if (!EFI_ERROR (Status
)) {
302 // Set the timer event
311 // Wait for the original event or the timer
314 WaitList
[1] = TimerEvent
;
315 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
316 gBS
->CloseEvent (TimerEvent
);
319 // If the timer expired, change the return to timed out
321 if (!EFI_ERROR (Status
) && Index
== 1) {
322 Status
= EFI_TIMEOUT
;
327 // Update screen every second
329 Timeout
= ONE_SECOND
;
332 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
335 // Set the timer event
344 // Wait for the original event or the timer
347 WaitList
[1] = TimerEvent
;
348 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
351 // If the timer expired, update anything that needs a refresh and keep waiting
353 if (!EFI_ERROR (Status
) && Index
== 1) {
354 Status
= EFI_TIMEOUT
;
355 UpdateDateAndTime ();
358 gBS
->CloseEvent (TimerEvent
);
359 } while (Status
== EFI_TIMEOUT
);
368 IN EFI_HII_HANDLE Handle
,
376 Add one menu option by specified description and context.
379 String - String description for this option.
380 Context - Context data for entry.
386 UI_MENU_OPTION
*MenuOption
;
388 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
391 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
392 MenuOption
->Description
= String
;
393 MenuOption
->Handle
= Handle
;
394 MenuOption
->FormBinary
= FormBinary
;
395 MenuOption
->IfrNumber
= IfrNumber
;
396 MenuOption
->Skip
= 1;
397 MenuOption
->Tags
= Tags
;
398 MenuOption
->TagIndex
= 0;
399 MenuOption
->ThisTag
= &(MenuOption
->Tags
[MenuOption
->TagIndex
]);
400 MenuOption
->EntryNumber
= (UINT16
) IfrNumber
;
402 InsertTailList (&Menu
, &MenuOption
->Link
);
408 IN EFI_HII_HANDLE Handle
,
412 IN UINT16 MenuItemCount
417 Add one menu option by specified description and context.
420 String - String description for this option.
421 Context - Context data for entry.
427 UI_MENU_OPTION
*MenuOption
;
429 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
432 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
433 MenuOption
->Description
= String
;
434 MenuOption
->Handle
= Handle
;
435 MenuOption
->Skip
= Tags
[TagIndex
].NumberOfLines
;
436 MenuOption
->IfrNumber
= gActiveIfr
;
437 MenuOption
->Tags
= Tags
;
438 MenuOption
->TagIndex
= TagIndex
;
439 MenuOption
->ThisTag
= &(MenuOption
->Tags
[MenuOption
->TagIndex
]);
440 MenuOption
->Consistency
= Tags
[TagIndex
].Consistency
;
441 MenuOption
->FormId
= FormId
;
442 MenuOption
->GrayOut
= Tags
[TagIndex
].GrayOut
;
443 MenuOption
->EntryNumber
= MenuItemCount
;
445 InsertTailList (&Menu
, &MenuOption
->Link
);
450 IN UINTN NumberOfLines
,
452 IN UINTN MaximumStringSize
,
453 OUT CHAR16
*StringBuffer
,
454 OUT EFI_INPUT_KEY
*KeyValue
,
461 Routine used to abstract a generic dialog interface and return the selected key or string
464 NumberOfLines - The number of lines for the dialog box
465 HotKey - Defines whether a single character is parsed (TRUE) and returned in KeyValue
466 or a string is returned in StringBuffer. Two special characters are considered when entering a string, a SCAN_ESC and
467 an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates string input and returns
468 MaximumStringSize - The maximum size in bytes of a typed in string (each character is a CHAR16) and the minimum string returned is two bytes
469 StringBuffer - The passed in pointer to the buffer which will hold the typed in string if HotKey is FALSE
470 KeyValue - The EFI_KEY value returned if HotKey is TRUE..
471 String - Pointer to the first string in the list
472 ... - A series of (quantity == NumberOfLines) text strings which will be used to construct the dialog box
475 EFI_SUCCESS - Displayed dialog and received user interaction
476 EFI_INVALID_PARAMETER - One of the parameters was invalid (e.g. (StringBuffer == NULL) && (HotKey == FALSE))
477 EFI_DEVICE_ERROR - User typed in an ESC character to exit the routine
486 CHAR16
*BufferedString
;
492 BOOLEAN SelectionComplete
;
494 UINTN CurrentAttribute
;
495 UINTN DimensionsWidth
;
496 UINTN DimensionsHeight
;
498 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
499 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
501 SelectionComplete
= FALSE
;
503 TempString
= AllocateZeroPool (MaximumStringSize
* 2);
504 BufferedString
= AllocateZeroPool (MaximumStringSize
* 2);
505 CurrentAttribute
= gST
->ConOut
->Mode
->Attribute
;
508 ASSERT (BufferedString
);
510 VA_START (Marker
, String
);
513 // Zero the outgoing buffer
515 ZeroMem (StringBuffer
, MaximumStringSize
);
518 if (KeyValue
== NULL
) {
519 return EFI_INVALID_PARAMETER
;
522 if (StringBuffer
== NULL
) {
523 return EFI_INVALID_PARAMETER
;
529 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
531 LargestString
= (GetStringWidth (String
) / 2);
533 if (LargestString
== L
' ') {
537 // Determine the largest string in the dialog box
538 // Notice we are starting with 1 since String is the first string
540 for (Count
= 1; Count
< NumberOfLines
; Count
++) {
541 StackString
= VA_ARG (Marker
, CHAR16
*);
543 if (StackString
[0] == L
' ') {
544 InputOffset
= Count
+ 1;
547 if ((GetStringWidth (StackString
) / 2) > LargestString
) {
549 // Size of the string visually and subtract the width by one for the null-terminator
551 LargestString
= (GetStringWidth (StackString
) / 2);
555 Start
= (DimensionsWidth
- LargestString
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
556 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
563 CreateSharedPopUp (LargestString
, NumberOfLines
, &String
);
566 // Take the first key typed and report it back?
569 WaitForKeyStroke (&Key
);
570 CopyMem (KeyValue
, &Key
, sizeof (EFI_INPUT_KEY
));
574 WaitForKeyStroke (&Key
);
576 switch (Key
.UnicodeChar
) {
578 switch (Key
.ScanCode
) {
580 FreePool (TempString
);
581 FreePool (BufferedString
);
582 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
583 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
584 return EFI_DEVICE_ERROR
;
592 case CHAR_CARRIAGE_RETURN
:
593 SelectionComplete
= TRUE
;
594 FreePool (TempString
);
595 FreePool (BufferedString
);
596 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
597 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
602 if (StringBuffer
[0] != CHAR_NULL
) {
603 for (Index
= 0; StringBuffer
[Index
] != CHAR_NULL
; Index
++) {
604 TempString
[Index
] = StringBuffer
[Index
];
607 // Effectively truncate string by 1 character
609 TempString
[Index
- 1] = CHAR_NULL
;
610 StrCpy (StringBuffer
, TempString
);
615 // If it is the beginning of the string, don't worry about checking maximum limits
617 if ((StringBuffer
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
618 StrnCpy (StringBuffer
, &Key
.UnicodeChar
, 1);
619 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
620 } else if ((GetStringWidth (StringBuffer
) < MaximumStringSize
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
621 KeyPad
[0] = Key
.UnicodeChar
;
622 KeyPad
[1] = CHAR_NULL
;
623 StrCat (StringBuffer
, KeyPad
);
624 StrCat (TempString
, KeyPad
);
627 // If the width of the input string is now larger than the screen, we nee to
628 // adjust the index to start printing portions of the string
630 SetUnicodeMem (BufferedString
, LargestString
, L
' ');
632 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
634 if ((GetStringWidth (StringBuffer
) / 2) > (DimensionsWidth
- 2)) {
635 Index
= (GetStringWidth (StringBuffer
) / 2) - DimensionsWidth
+ 2;
640 for (Count
= 0; Index
+ 1 < GetStringWidth (StringBuffer
) / 2; Index
++, Count
++) {
641 BufferedString
[Count
] = StringBuffer
[Index
];
644 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
647 } while (!SelectionComplete
);
650 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
651 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
657 IN UINTN RequestedWidth
,
658 IN UINTN NumberOfLines
,
659 IN CHAR16
**ArrayOfStrings
671 UINTN DimensionsWidth
;
672 UINTN DimensionsHeight
;
674 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
675 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
679 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
681 if ((RequestedWidth
+ 2) > DimensionsWidth
) {
682 RequestedWidth
= DimensionsWidth
- 2;
685 // Subtract the PopUp width from total Columns, allow for one space extra on
686 // each end plus a border.
688 Start
= (DimensionsWidth
- RequestedWidth
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
689 End
= Start
+ RequestedWidth
+ 1;
691 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
692 Bottom
= Top
+ NumberOfLines
+ 2;
694 Character
= (CHAR16
) BOXDRAW_DOWN_RIGHT
;
695 PrintCharAt (Start
, Top
, Character
);
696 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
697 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
698 PrintChar (Character
);
701 Character
= (CHAR16
) BOXDRAW_DOWN_LEFT
;
702 PrintChar (Character
);
703 Character
= (CHAR16
) BOXDRAW_VERTICAL
;
704 for (Index
= Top
; Index
+ 2 < Bottom
; Index
++) {
705 String
= ArrayOfStrings
[Count
];
709 // This will clear the background of the line - we never know who might have been
710 // here before us. This differs from the next clear in that it used the non-reverse
711 // video for normal printing.
713 if (GetStringWidth (String
) / 2 > 1) {
714 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
717 // Passing in a space results in the assumption that this is where typing will occur
719 if (String
[0] == L
' ') {
720 ClearLines (Start
+ 1, End
- 1, Index
+ 1, Index
+ 1, POPUP_INVERSE_TEXT
| POPUP_INVERSE_BACKGROUND
);
723 // Passing in a NULL results in a blank space
725 if (String
[0] == CHAR_NULL
) {
726 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
730 ((DimensionsWidth
- GetStringWidth (String
) / 2) / 2) + gScreenDimensions
.LeftColumn
+ 1,
734 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
735 PrintCharAt (Start
, Index
+ 1, Character
);
736 PrintCharAt (End
- 1, Index
+ 1, Character
);
739 Character
= (CHAR16
) BOXDRAW_UP_RIGHT
;
740 PrintCharAt (Start
, Bottom
- 1, Character
);
741 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
742 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
743 PrintChar (Character
);
746 Character
= (CHAR16
) BOXDRAW_UP_LEFT
;
747 PrintChar (Character
);
752 IN UINTN RequestedWidth
,
753 IN UINTN NumberOfLines
,
754 IN CHAR16
*ArrayOfStrings
,
758 CreateSharedPopUp (RequestedWidth
, NumberOfLines
, &ArrayOfStrings
);
763 IN UINTN MessageType
,
769 STATIC BOOLEAN InputError
;
770 CHAR16
*NvUpdateMessage
;
771 CHAR16
*InputErrorMessage
;
773 NvUpdateMessage
= GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE
), gHiiHandle
);
774 InputErrorMessage
= GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE
), gHiiHandle
);
776 switch (MessageType
) {
779 gST
->ConOut
->SetAttribute (gST
->ConOut
, ERROR_TEXT
);
781 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
,
782 gScreenDimensions
.BottomRow
- 1,
787 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
);
788 for (Index
= 0; Index
< (GetStringWidth (InputErrorMessage
) - 2) / 2; Index
++) {
789 PrintAt (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ Index
, gScreenDimensions
.BottomRow
- 1, (CHAR16
*) L
" ");
796 case NV_UPDATE_REQUIRED
:
797 if (gClassOfVfr
!= EFI_FRONT_PAGE_SUBCLASS
) {
799 gST
->ConOut
->SetAttribute (gST
->ConOut
, INFO_TEXT
);
801 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
802 gScreenDimensions
.BottomRow
- 1,
805 gResetRequired
= (BOOLEAN
) (gResetRequired
| ((Flags
& EFI_IFR_FLAG_RESET_REQUIRED
) == EFI_IFR_FLAG_RESET_REQUIRED
));
807 gNvUpdateRequired
= TRUE
;
809 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
);
810 for (Index
= 0; Index
< (GetStringWidth (NvUpdateMessage
) - 2) / 2; Index
++) {
812 (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ Index
),
813 gScreenDimensions
.BottomRow
- 1,
818 gNvUpdateRequired
= FALSE
;
823 case REFRESH_STATUS_BAR
:
825 UpdateStatusBar (INPUT_ERROR
, Flags
, TRUE
);
828 if (gNvUpdateRequired
) {
829 UpdateStatusBar (NV_UPDATE_REQUIRED
, Flags
, TRUE
);
837 FreePool (InputErrorMessage
);
838 FreePool (NvUpdateMessage
);
844 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
845 IN CHAR16
*FormattedString
,
846 IN CHAR16
*OptionString
852 Used to remove the allocated data instances
860 EFI_FILE_FORM_TAGS
*FileForm
;
861 EFI_FILE_FORM_TAGS
*PreviousFileForm
;
862 EFI_FORM_TAGS
*FormTags
;
863 EFI_FORM_TAGS
*PreviousFormTags
;
864 EFI_IFR_BINARY
*IfrBinary
;
865 EFI_IFR_BINARY
*PreviousIfrBinary
;
866 EFI_INCONSISTENCY_DATA
*Inconsistent
;
867 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
868 EFI_VARIABLE_DEFINITION
*PreviousVariableDefinition
;
872 FileForm
= FileFormTagsHead
;
874 if (FormattedString
!= NULL
) {
875 FreePool (FormattedString
);
878 if (OptionString
!= NULL
) {
879 FreePool (OptionString
);
882 for (; FileForm
!= NULL
;) {
883 PreviousFileForm
= NULL
;
886 // Advance FileForm to the last entry
888 for (; FileForm
->NextFile
!= NULL
; FileForm
= FileForm
->NextFile
) {
889 PreviousFileForm
= FileForm
;
892 FormTags
= &FileForm
->FormTags
;
894 for (; FormTags
!= NULL
;) {
895 FormTags
= &FileForm
->FormTags
;
896 PreviousFormTags
= NULL
;
899 // Advance FormTags to the last entry
901 for (; FormTags
->Next
!= NULL
; FormTags
= FormTags
->Next
) {
902 PreviousFormTags
= FormTags
;
905 // Walk through each of the tags and free the IntList allocation
907 for (Index
= 0; FormTags
->Tags
[Index
].Operand
!= EFI_IFR_END_FORM_OP
; Index
++) {
909 // It is more than likely that the very last page will contain an end formset
911 if (FormTags
->Tags
[Index
].Operand
== EFI_IFR_END_FORM_SET_OP
) {
915 if (FormTags
->Tags
[Index
].IntList
!= NULL
) {
916 FreePool (FormTags
->Tags
[Index
].IntList
);
920 if (PreviousFormTags
!= NULL
) {
921 FreePool (FormTags
->Tags
);
922 FormTags
= PreviousFormTags
;
923 FreePool (FormTags
->Next
);
924 FormTags
->Next
= NULL
;
926 FreePool (FormTags
->Tags
);
931 // Last FileForm entry's Inconsistent database
933 Inconsistent
= FileForm
->InconsistentTags
;
936 // Advance Inconsistent to the last entry
938 for (; Inconsistent
->Next
!= NULL
; Inconsistent
= Inconsistent
->Next
)
941 for (; Inconsistent
!= NULL
;) {
943 // Preserve the Previous pointer
945 Buffer
= (VOID
*) Inconsistent
->Previous
;
948 // Free the current entry
950 FreePool (Inconsistent
);
953 // Restore the Previous pointer
955 Inconsistent
= (EFI_INCONSISTENCY_DATA
*) Buffer
;
958 VariableDefinition
= FileForm
->VariableDefinitions
;
960 for (; VariableDefinition
!= NULL
;) {
961 VariableDefinition
= FileForm
->VariableDefinitions
;
962 PreviousVariableDefinition
= NULL
;
965 // Advance VariableDefinitions to the last entry
967 for (; VariableDefinition
->Next
!= NULL
; VariableDefinition
= VariableDefinition
->Next
) {
968 PreviousVariableDefinition
= VariableDefinition
;
971 FreePool (VariableDefinition
->VariableName
);
973 if (VariableDefinition
->NvRamMap
!= NULL
) {
974 FreePool (VariableDefinition
->NvRamMap
);
977 if (VariableDefinition
->FakeNvRamMap
!= NULL
) {
978 FreePool (VariableDefinition
->FakeNvRamMap
);
981 if (PreviousVariableDefinition
!= NULL
) {
982 VariableDefinition
= PreviousVariableDefinition
;
983 FreePool (VariableDefinition
->Next
);
984 VariableDefinition
->Next
= NULL
;
986 FreePool (VariableDefinition
);
987 VariableDefinition
= NULL
;
991 if (PreviousFileForm
!= NULL
) {
992 FileForm
= PreviousFileForm
;
993 FreePool (FileForm
->NextFile
);
994 FileForm
->NextFile
= NULL
;
1001 IfrBinary
= gBinaryDataHead
;
1003 for (; IfrBinary
!= NULL
;) {
1004 IfrBinary
= gBinaryDataHead
;
1005 PreviousIfrBinary
= NULL
;
1008 // Advance IfrBinary to the last entry
1010 for (; IfrBinary
->Next
!= NULL
; IfrBinary
= IfrBinary
->Next
) {
1011 PreviousIfrBinary
= IfrBinary
;
1014 FreePool (IfrBinary
->IfrPackage
);
1016 if (PreviousIfrBinary
!= NULL
) {
1017 IfrBinary
= PreviousIfrBinary
;
1018 FreePool (IfrBinary
->Next
);
1019 IfrBinary
->Next
= NULL
;
1021 FreePool (IfrBinary
);
1026 FreePool (gPreviousValue
);
1027 gPreviousValue
= NULL
;
1030 // Free Browser Strings
1032 FreePool (gPressEnter
);
1033 FreePool (gConfirmError
);
1034 FreePool (gConfirmPassword
);
1035 FreePool (gPromptForNewPassword
);
1036 FreePool (gPromptForPassword
);
1037 FreePool (gToggleCheckBox
);
1038 FreePool (gNumericInput
);
1039 FreePool (gMakeSelection
);
1040 FreePool (gMoveHighlight
);
1041 FreePool (gEscapeString
);
1042 FreePool (gEnterCommitString
);
1043 FreePool (gEnterString
);
1044 FreePool (gFunctionOneString
);
1045 FreePool (gFunctionTwoString
);
1046 FreePool (gFunctionNineString
);
1047 FreePool (gFunctionTenString
);
1053 SelectionsAreValid (
1054 IN UI_MENU_OPTION
*MenuOption
,
1055 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
1059 Routine Description:
1060 Initiate late consistency checks against the current page.
1071 EFI_FILE_FORM_TAGS
*FileFormTags
;
1073 CHAR16 NullCharacter
;
1078 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
1080 StringPtr
= (CHAR16
*) L
"\0";
1081 NullCharacter
= CHAR_NULL
;
1083 FileFormTags
= FileFormTagsHead
;
1085 for (Index
= 0; Index
< MenuOption
->IfrNumber
; Index
++) {
1086 FileFormTags
= FileFormTags
->NextFile
;
1089 for (Link
= Menu
.ForwardLink
; Link
!= &Menu
; Link
= Link
->ForwardLink
) {
1090 MenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
1092 Tag
= MenuOption
->ThisTag
;
1094 ExtractRequestedNvMap (FileFormTags
, Tag
->VariableNumber
, &VariableDefinition
);
1095 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
1098 // If the op-code has a late check, ensure consistency checks are now applied
1100 if (Tag
->Flags
& EFI_IFR_FLAG_LATE_CHECK
) {
1101 if (ValueIsNotValid (TRUE
, 0, Tag
, FileFormTags
, &PopUp
)) {
1102 if (PopUp
!= 0x0000) {
1103 StringPtr
= GetToken (PopUp
, MenuOption
->Handle
);
1105 CreatePopUp (GetStringWidth (StringPtr
) / 2, 3, &NullCharacter
, StringPtr
, &NullCharacter
);
1108 WaitForKeyStroke (&Key
);
1110 switch (Key
.UnicodeChar
) {
1112 case CHAR_CARRIAGE_RETURN
:
1114 // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
1116 CopyMem (NvRamMap
, &Tag
->OldValue
, Tag
->StorageWidth
);
1117 FreePool (StringPtr
);
1123 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1137 IN EFI_HII_HANDLE Handle
1141 Routine Description:
1142 Get the supported width for a particular op-code
1145 Tag - The Tag structure passed in.
1146 Handle - The handle in the HII database being used
1149 Returns the number of CHAR16 characters that is support.
1160 // See if the second text parameter is really NULL
1162 if ((Tag
->Operand
== EFI_IFR_TEXT_OP
) && (Tag
->TextTwo
!= 0)) {
1163 String
= GetToken (Tag
->TextTwo
, Handle
);
1164 Size
= StrLen (String
);
1168 if ((Tag
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1169 (Tag
->Operand
== EFI_IFR_REF_OP
) ||
1170 (Tag
->Operand
== EFI_IFR_PASSWORD_OP
) ||
1171 (Tag
->Operand
== EFI_IFR_STRING_OP
) ||
1172 (Tag
->Operand
== EFI_IFR_INVENTORY_OP
) ||
1174 // Allow a wide display if text op-code and no secondary text op-code
1176 ((Tag
->Operand
== EFI_IFR_TEXT_OP
) && (Size
== 0x0000))
1178 return (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
);
1180 return (UINT16
) gPromptBlockWidth
;
1186 IN CHAR16
*InputString
,
1187 IN UINT16 LineWidth
,
1188 IN OUT UINTN
*Index
,
1189 OUT CHAR16
**OutputString
1193 Routine Description:
1194 Will copy LineWidth amount of a string in the OutputString buffer and return the
1195 number of CHAR16 characters that were copied into the OutputString buffer.
1198 InputString - String description for this option.
1199 LineWidth - Width of the desired string to extract in CHAR16 characters
1200 Index - Where in InputString to start the copy process
1201 OutputString - Buffer to copy the string into
1204 Returns the number of CHAR16 characters that were copied into the OutputString buffer.
1209 static BOOLEAN Finished
;
1221 *OutputString
= AllocateZeroPool (((UINTN
) (LineWidth
+ 1) * 2));
1224 // Ensure we have got a valid buffer
1226 if (*OutputString
!= NULL
) {
1229 //NARROW_CHAR can not be printed in screen, so if a line only contain the two CHARs: 'NARROW_CHAR + CHAR_CARRIAGE_RETURN' , it is a empty line in Screen.
1230 //To avoid displaying this empty line in screen, just skip the two CHARs here.
1232 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
1233 *Index
= *Index
+ 2;
1237 // Fast-forward the string and see if there is a carriage-return in the string
1239 for (; (InputString
[*Index
+ Count2
] != CHAR_CARRIAGE_RETURN
) && (Count2
!= LineWidth
); Count2
++)
1243 // Copy the desired LineWidth of data to the output buffer.
1244 // Also make sure that we don't copy more than the string.
1245 // Also make sure that if there are linefeeds, we account for them.
1247 if ((StrSize (&InputString
[*Index
]) <= ((UINTN
) (LineWidth
+ 1) * 2)) &&
1248 (StrSize (&InputString
[*Index
]) <= ((UINTN
) (Count2
+ 1) * 2))
1251 // Convert to CHAR16 value and show that we are done with this operation
1253 LineWidth
= (UINT16
) ((StrSize (&InputString
[*Index
]) - 2) / 2);
1254 if (LineWidth
!= 0) {
1258 if (Count2
== LineWidth
) {
1260 // Rewind the string from the maximum size until we see a space to break the line
1262 for (; (InputString
[*Index
+ LineWidth
] != CHAR_SPACE
) && (LineWidth
!= 0); LineWidth
--)
1264 if (LineWidth
== 0) {
1272 CopyMem (*OutputString
, &InputString
[*Index
], LineWidth
* 2);
1275 // If currently pointing to a space, increment the index to the first non-space character
1278 (InputString
[*Index
+ LineWidth
] == CHAR_SPACE
) || (InputString
[*Index
+ LineWidth
] == CHAR_CARRIAGE_RETURN
);
1282 *Index
= (UINT16
) (*Index
+ LineWidth
);
1291 UpdateOptionSkipLines (
1292 IN EFI_IFR_DATA_ARRAY
*PageData
,
1293 IN UI_MENU_OPTION
*MenuOption
,
1294 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
1295 IN CHAR16
**OptionalString
,
1303 CHAR16
*OutputString
;
1304 CHAR16
*OptionString
;
1307 OptionString
= *OptionalString
;
1308 OutputString
= NULL
;
1310 ProcessOptions (MenuOption
, FALSE
, FileFormTagsHead
, PageData
, &OptionString
);
1312 if (OptionString
!= NULL
) {
1313 Width
= (UINT16
) gOptionBlockWidth
;
1317 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1319 // If there is more string to process print on the next row and increment the Skip value
1321 if (StrLen (&OptionString
[Index
])) {
1322 if (SkipValue
== 0) {
1325 // Since the Number of lines for this menu entry may or may not be reflected accurately
1326 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1327 // some testing to ensure we are keeping this in-sync.
1329 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1331 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1337 FreePool (OutputString
);
1338 if (SkipValue
!= 0) {
1346 *OptionalString
= OptionString
;
1349 // Search table for UiDisplayMenu()
1351 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation
[] = {
1353 { SCAN_DOWN
, UiDown
},
1354 { SCAN_PAGE_UP
, UiPageUp
},
1355 { SCAN_PAGE_DOWN
, UiPageDown
},
1356 { SCAN_ESC
, UiReset
},
1357 { SCAN_F2
, UiPrevious
},
1358 { SCAN_LEFT
, UiLeft
},
1359 { SCAN_RIGHT
, UiRight
},
1360 { SCAN_F9
, UiDefault
},
1361 { SCAN_F10
, UiSave
}
1364 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag
[] = {
1365 { UiNoOperation
, CfUiNoOperation
},
1366 { UiDefault
, CfUiDefault
},
1367 { UiSelect
, CfUiSelect
},
1369 { UiDown
, CfUiDown
},
1370 { UiLeft
, CfUiLeft
},
1371 { UiRight
, CfUiRight
},
1372 { UiReset
, CfUiReset
},
1373 { UiSave
, CfUiSave
},
1374 { UiPrevious
, CfUiPrevious
},
1375 { UiPageUp
, CfUiPageUp
},
1376 { UiPageDown
, CfUiPageDown
}
1382 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
1383 OUT EFI_IFR_DATA_ARRAY
*PageData
1387 Routine Description:
1388 Display menu and wait for user to select one menu option, then return it.
1389 If AutoBoot is enabled, then if user doesn't select any option,
1390 after period of time, it will automatically return the first menu option.
1393 SubMenu - Indicate is sub menu.
1394 FileFormTagsHead - A pointer to the EFI_FILE_FORM_TAGS structure.
1395 PageData - A pointer to the EFI_IFR_DATA_ARRAY.
1398 Return the pointer of the menu which selected,
1399 otherwise return NULL.
1414 UINTN DataAndTimeLineNumberPad
;
1416 INT16 OriginalTimeOut
;
1420 CHAR16
*OptionString
;
1421 CHAR16
*OutputString
;
1422 CHAR16
*FormattedString
;
1429 UI_MENU_LIST
*UiMenuList
;
1433 LIST_ENTRY
*TopOfScreen
;
1434 LIST_ENTRY
*SavedListEntry
;
1435 UI_MENU_OPTION
*Selection
;
1436 UI_MENU_OPTION
*MenuOption
;
1437 UI_MENU_OPTION
*NextMenuOption
;
1438 UI_MENU_OPTION
*SavedMenuOption
;
1439 UI_MENU_OPTION
*PreviousMenuOption
;
1440 EFI_IFR_BINARY
*IfrBinary
;
1441 UI_CONTROL_FLAG ControlFlag
;
1442 EFI_SCREEN_DESCRIPTOR LocalScreen
;
1443 EFI_FILE_FORM_TAGS
*FileFormTags
;
1444 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
1445 MENU_REFRESH_ENTRY
*OldMenuRefreshEntry
;
1446 UI_SCREEN_OPERATION ScreenOperation
;
1447 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
1448 EFI_FORM_CALLBACK_PROTOCOL
*FormCallback
;
1449 EFI_HII_VARIABLE_PACK_LIST
*NvMapListHead
;
1450 EFI_HII_VARIABLE_PACK_LIST
*NvMapListNode
;
1454 CopyMem (&LocalScreen
, &gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
1456 VariableDefinition
= NULL
;
1457 Status
= EFI_SUCCESS
;
1458 FormattedString
= NULL
;
1459 OptionString
= NULL
;
1460 ScreenOperation
= UiNoOperation
;
1462 FormCallback
= NULL
;
1463 FileFormTags
= NULL
;
1464 OutputString
= NULL
;
1469 MenuRefreshEntry
= gMenuRefreshHead
;
1470 OldMenuRefreshEntry
= gMenuRefreshHead
;
1471 NextMenuOption
= NULL
;
1472 PreviousMenuOption
= NULL
;
1473 SavedMenuOption
= NULL
;
1478 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
1480 if (gClassOfVfr
== EFI_FRONT_PAGE_SUBCLASS
) {
1481 TopRow
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1482 Row
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1484 TopRow
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1485 Row
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1489 Col
= LocalScreen
.LeftColumn
;
1491 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
1494 BottomRow
= LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
- SCROLL_ARROW_HEIGHT
- 1;
1496 TopOfScreen
= Menu
.ForwardLink
;
1501 // Get user's selection
1504 NewPos
= Menu
.ForwardLink
;
1505 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
1507 UpdateStatusBar (REFRESH_STATUS_BAR
, (UINT8
) 0, TRUE
);
1509 ControlFlag
= CfInitialization
;
1512 switch (ControlFlag
) {
1513 case CfInitialization
:
1514 ControlFlag
= CfCheckSelection
;
1515 if (gExitRequired
) {
1516 ScreenOperation
= UiReset
;
1517 ControlFlag
= CfScreenOperation
;
1518 } else if (gSaveRequired
) {
1519 ScreenOperation
= UiSave
;
1520 ControlFlag
= CfScreenOperation
;
1521 } else if (IsListEmpty (&Menu
)) {
1522 ControlFlag
= CfReadKey
;
1526 case CfCheckSelection
:
1527 if (Selection
!= NULL
) {
1528 ControlFlag
= CfExit
;
1530 ControlFlag
= CfRepaint
;
1533 FileFormTags
= FileFormTagsHead
;
1537 ControlFlag
= CfRefreshHighLight
;
1543 SavedMenuOption
= MenuOption
;
1552 LocalScreen
.LeftColumn
,
1553 LocalScreen
.RightColumn
,
1554 TopRow
- SCROLL_ARROW_HEIGHT
,
1555 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1556 FIELD_TEXT
| FIELD_BACKGROUND
1559 while (gMenuRefreshHead
!= NULL
) {
1560 OldMenuRefreshEntry
= gMenuRefreshHead
->Next
;
1562 FreePool (gMenuRefreshHead
);
1564 gMenuRefreshHead
= OldMenuRefreshEntry
;
1567 for (Link
= TopOfScreen
; Link
!= &Menu
; Link
= Link
->ForwardLink
) {
1568 MenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
1569 MenuOption
->Row
= Row
;
1571 MenuOption
->Col
= Col
;
1572 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
1575 if (MenuOption
->ThisTag
->GrayOut
) {
1576 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
1578 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
1579 gST
->ConOut
->SetAttribute (gST
->ConOut
, SUBTITLE_TEXT
| FIELD_BACKGROUND
);
1583 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
1587 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
1588 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1589 PrintStringAt (Col
, Row
, OutputString
);
1592 // If there is more string to process print on the next row and increment the Skip value
1594 if (StrLen (&MenuOption
->Description
[Index
])) {
1600 FreePool (OutputString
);
1610 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1611 ProcessOptions (MenuOption
, FALSE
, FileFormTagsHead
, PageData
, &OptionString
);
1613 if (OptionString
!= NULL
) {
1614 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
1615 MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
1618 // If leading spaces on OptionString - remove the spaces
1620 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
1621 MenuOption
->OptCol
++;
1624 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1625 OptionString
[Count
] = OptionString
[Index
];
1629 OptionString
[Count
] = CHAR_NULL
;
1633 // If this is a date or time op-code and is used to reflect an RTC, register the op-code
1635 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
1636 MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
) &&
1637 (MenuOption
->ThisTag
->StorageStart
>= FileFormTags
->FormTags
.Tags
[0].NvDataSize
)) {
1639 if (gMenuRefreshHead
== NULL
) {
1640 MenuRefreshEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1641 ASSERT (MenuRefreshEntry
!= NULL
);
1642 MenuRefreshEntry
->MenuOption
= MenuOption
;
1643 MenuRefreshEntry
->FileFormTagsHead
= FileFormTagsHead
;
1644 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1645 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1646 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT
| FIELD_BACKGROUND
;
1647 gMenuRefreshHead
= MenuRefreshEntry
;
1650 // Advance to the last entry
1652 for (MenuRefreshEntry
= gMenuRefreshHead
;
1653 MenuRefreshEntry
->Next
!= NULL
;
1654 MenuRefreshEntry
= MenuRefreshEntry
->Next
1657 MenuRefreshEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1658 ASSERT (MenuRefreshEntry
->Next
!= NULL
);
1659 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
1660 MenuRefreshEntry
->MenuOption
= MenuOption
;
1661 MenuRefreshEntry
->FileFormTagsHead
= FileFormTagsHead
;
1662 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1663 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1664 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT
| FIELD_BACKGROUND
;
1668 Width
= (UINT16
) gOptionBlockWidth
;
1672 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1673 if ((Temp2
== 0) && (Row
<= BottomRow
)) {
1674 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1677 // If there is more string to process print on the next row and increment the Skip value
1679 if (StrLen (&OptionString
[Index
])) {
1683 // Since the Number of lines for this menu entry may or may not be reflected accurately
1684 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1685 // some testing to ensure we are keeping this in-sync.
1687 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1689 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1695 FreePool (OutputString
);
1705 // If this is a text op with secondary text information
1707 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_TEXT_OP
) && (MenuOption
->ThisTag
->TextTwo
!= 0)) {
1708 StringPtr
= GetToken (MenuOption
->ThisTag
->TextTwo
, MenuOption
->Handle
);
1710 Width
= (UINT16
) gOptionBlockWidth
;
1714 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &Index
, &OutputString
) != 0x0000;) {
1715 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1716 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1719 // If there is more string to process print on the next row and increment the Skip value
1721 if (StrLen (&StringPtr
[Index
])) {
1725 // Since the Number of lines for this menu entry may or may not be reflected accurately
1726 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1727 // some testing to ensure we are keeping this in-sync.
1729 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1731 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1737 FreePool (OutputString
);
1744 FreePool (StringPtr
);
1748 // For now, assume left-justified 72 width max setup entries
1750 PrintStringAt (Col
, Row
, MenuOption
->Description
);
1753 // Tracker 6210 - need to handle the bottom of the display
1755 if (MenuOption
->Skip
> 1) {
1756 Row
+= MenuOption
->Skip
- SkipValue
;
1759 Row
+= MenuOption
->Skip
;
1762 if (Row
> BottomRow
) {
1763 if (!ValueIsScroll (FALSE
, Link
)) {
1767 Row
= BottomRow
+ 1;
1772 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
1777 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
1779 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
1780 TopRow
- SCROLL_ARROW_HEIGHT
,
1784 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1788 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
1790 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
1791 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1795 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1798 if (SavedMenuOption
!= NULL
) {
1799 MenuOption
= SavedMenuOption
;
1804 case CfRefreshHighLight
:
1805 ControlFlag
= CfUpdateHelpString
;
1807 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily
1808 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.
1810 SavedValue
= Repaint
;
1813 if (NewPos
!= NULL
) {
1814 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
1816 if (gLastOpr
&& (gEntryNumber
!= -1)) {
1817 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
1818 if (gEntryNumber
!= MenuOption
->EntryNumber
) {
1819 ScreenOperation
= UiDown
;
1820 ControlFlag
= CfScreenOperation
;
1827 ProcessOptions (MenuOption
, FALSE
, FileFormTagsHead
, PageData
, &OptionString
);
1828 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1829 if (OptionString
!= NULL
) {
1830 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
1831 MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
1834 // If leading spaces on OptionString - remove the spaces
1836 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
1839 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1840 OptionString
[Count
] = OptionString
[Index
];
1844 OptionString
[Count
] = CHAR_NULL
;
1847 Width
= (UINT16
) gOptionBlockWidth
;
1849 OriginalRow
= MenuOption
->Row
;
1851 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1852 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
1853 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
1856 // If there is more string to process print on the next row and increment the Skip value
1858 if (StrLen (&OptionString
[Index
])) {
1862 FreePool (OutputString
);
1865 MenuOption
->Row
= OriginalRow
;
1868 if (MenuOption
->ThisTag
->GrayOut
) {
1869 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
1871 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
1872 gST
->ConOut
->SetAttribute (gST
->ConOut
, SUBTITLE_TEXT
| FIELD_BACKGROUND
);
1876 OriginalRow
= MenuOption
->Row
;
1877 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
1879 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
1880 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
1881 PrintStringAt (Col
, MenuOption
->Row
, OutputString
);
1884 // If there is more string to process print on the next row and increment the Skip value
1886 if (StrLen (&MenuOption
->Description
[Index
])) {
1890 FreePool (OutputString
);
1893 MenuOption
->Row
= OriginalRow
;
1894 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1898 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1899 gST
->ConOut
->OutputString (gST
->ConOut
, MenuOption
->Description
);
1902 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
1904 if ((gPriorMenuEntry
!= 0) && (MenuOption
->EntryNumber
!= gPriorMenuEntry
) && (NewPos
->ForwardLink
!= &Menu
)) {
1905 ScreenOperation
= UiDown
;
1906 ControlFlag
= CfScreenOperation
;
1909 gPriorMenuEntry
= 0;
1912 // This is only possible if we entered this page and the first menu option is
1913 // a "non-menu" item. In that case, force it UiDown
1915 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| MenuOption
->ThisTag
->GrayOut
) {
1917 // If we previously hit an UP command and we are still sitting on a text operation
1918 // we must continue going up
1920 if (ScreenOperation
== UiUp
) {
1921 ControlFlag
= CfScreenOperation
;
1924 ScreenOperation
= UiDown
;
1925 ControlFlag
= CfScreenOperation
;
1930 // Set reverse attribute
1932 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
| FIELD_BACKGROUND_HIGHLIGHT
);
1933 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
1936 // Assuming that we have a refresh linked-list created, lets annotate the
1937 // appropriate entry that we are highlighting with its new attribute. Just prior to this
1938 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh
1940 if (gMenuRefreshHead
!= NULL
) {
1941 for (MenuRefreshEntry
= gMenuRefreshHead
; MenuRefreshEntry
!= NULL
; MenuRefreshEntry
= MenuRefreshEntry
->Next
) {
1942 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT
| FIELD_BACKGROUND
;
1943 if (MenuRefreshEntry
->MenuOption
== MenuOption
) {
1944 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_HIGHLIGHT
| FIELD_BACKGROUND_HIGHLIGHT
;
1950 ProcessOptions (MenuOption
, FALSE
, FileFormTagsHead
, PageData
, &OptionString
);
1951 if (OptionString
!= NULL
) {
1952 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
1953 MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
1956 // If leading spaces on OptionString - remove the spaces
1958 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
1961 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1962 OptionString
[Count
] = OptionString
[Index
];
1966 OptionString
[Count
] = CHAR_NULL
;
1968 Width
= (UINT16
) gOptionBlockWidth
;
1970 OriginalRow
= MenuOption
->Row
;
1972 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1973 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
1974 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
1977 // If there is more string to process print on the next row and increment the Skip value
1979 if (StrLen (&OptionString
[Index
])) {
1983 FreePool (OutputString
);
1986 MenuOption
->Row
= OriginalRow
;
1989 OriginalRow
= MenuOption
->Row
;
1991 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
1993 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
1994 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
1995 PrintStringAt (Col
, MenuOption
->Row
, OutputString
);
1998 // If there is more string to process print on the next row and increment the Skip value
2000 if (StrLen (&MenuOption
->Description
[Index
])) {
2004 FreePool (OutputString
);
2007 MenuOption
->Row
= OriginalRow
;
2012 if (((NewPos
->ForwardLink
!= &Menu
) && (ScreenOperation
== UiDown
)) ||
2013 ((NewPos
->BackLink
!= &Menu
) && (ScreenOperation
== UiUp
)) ||
2014 (ScreenOperation
== UiNoOperation
)
2016 UpdateKeyHelp (MenuOption
, FALSE
);
2019 gST
->ConOut
->OutputString (gST
->ConOut
, MenuOption
->Description
);
2022 // Clear reverse attribute
2024 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
2027 // Repaint flag will be used when process CfUpdateHelpString, so restore its value
2028 // if we didn't break halfway when process CfRefreshHighLight.
2030 Repaint
= SavedValue
;
2033 case CfUpdateHelpString
:
2034 ControlFlag
= CfPrepareToReadKey
;
2037 (Repaint
|| NewLine
||
2038 (MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2039 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) &&
2040 !(gClassOfVfr
== EFI_GENERAL_APPLICATION_SUBCLASS
)) {
2042 // Don't print anything if it is a NULL help token
2044 if (MenuOption
->ThisTag
->Help
== 0x00000000) {
2045 StringPtr
= (CHAR16
*) L
"\0";
2047 StringPtr
= GetToken (MenuOption
->ThisTag
->Help
, MenuOption
->Handle
);
2050 ProcessHelpString (StringPtr
, &FormattedString
, BottomRow
- TopRow
);
2052 gST
->ConOut
->SetAttribute (gST
->ConOut
, HELP_TEXT
| FIELD_BACKGROUND
);
2054 for (Index
= 0; Index
< BottomRow
- TopRow
; Index
++) {
2056 // Pad String with spaces to simulate a clearing of the previous line
2058 for (; GetStringWidth (&FormattedString
[Index
* gHelpBlockWidth
* 2]) / 2 < gHelpBlockWidth
;) {
2059 StrCat (&FormattedString
[Index
* gHelpBlockWidth
* 2], (CHAR16
*) L
" ");
2063 LocalScreen
.RightColumn
- gHelpBlockWidth
,
2065 &FormattedString
[Index
* gHelpBlockWidth
* 2]
2070 // Reset this flag every time we finish using it.
2076 case CfPrepareToReadKey
:
2077 ControlFlag
= CfReadKey
;
2079 for (Index
= 0; Index
< MenuOption
->IfrNumber
; Index
++) {
2080 FileFormTags
= FileFormTags
->NextFile
;
2083 ScreenOperation
= UiNoOperation
;
2085 Status
= gBS
->HandleProtocol (
2086 (VOID
*) (UINTN
) FileFormTags
->FormTags
.Tags
[0].CallbackHandle
,
2087 &gEfiFormCallbackProtocolGuid
,
2088 (VOID
**) &FormCallback
2094 ControlFlag
= CfScreenOperation
;
2096 OriginalTimeOut
= FrontPageTimeOutValue
;
2098 if (FrontPageTimeOutValue
>= 0 && (gClassOfVfr
== EFI_FRONT_PAGE_SUBCLASS
) && FrontPageTimeOutValue
!= (INT16
) -1) {
2100 // Remember that if set to 0, must immediately boot an option
2102 if (FrontPageTimeOutValue
== 0) {
2103 FrontPageTimeOutValue
= 0xFFFF;
2104 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2105 if (EFI_ERROR (Status
)) {
2106 Status
= EFI_TIMEOUT
;
2111 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, ONE_SECOND
);
2112 if (Status
== EFI_TIMEOUT
) {
2113 EFI_IFR_DATA_ENTRY
*DataEntry
;
2115 DataEntry
= (EFI_IFR_DATA_ENTRY
*) (PageData
+ 1);
2117 PageData
->EntryCount
= 1;
2118 Count
= (UINT32
) ((OriginalTimeOut
- FrontPageTimeOutValue
) * 100 / OriginalTimeOut
);
2119 CopyMem (&DataEntry
->Data
, &Count
, sizeof (UINT32
));
2121 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
2122 FormCallback
->Callback (
2125 (EFI_IFR_DATA_ARRAY
*) PageData
,
2130 // Count down 1 second
2132 FrontPageTimeOutValue
--;
2135 ASSERT (!EFI_ERROR (Status
));
2136 PageData
->EntryCount
= 0;
2137 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
2138 FormCallback
->Callback (
2141 (EFI_IFR_DATA_ARRAY
*) PageData
,
2146 FrontPageTimeOutValue
= 0xFFFF;
2150 // Wait for user's selection, no auto boot
2152 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0);
2154 } while (Status
== EFI_TIMEOUT
);
2158 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
2159 DisableQuietBoot ();
2162 if (Status
== EFI_TIMEOUT
) {
2163 Key
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
2165 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2167 // if we encounter error, continue to read another key in.
2169 if (EFI_ERROR (Status
)) {
2170 ControlFlag
= CfReadKey
;
2175 switch (Key
.UnicodeChar
) {
2176 case CHAR_CARRIAGE_RETURN
:
2177 Selection
= MenuOption
;
2178 ScreenOperation
= UiSelect
;
2183 // We will push the adjustment of these numeric values directly to the input handler
2187 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2189 if (Key
.UnicodeChar
== '+') {
2190 gDirection
= SCAN_RIGHT
;
2192 gDirection
= SCAN_LEFT
;
2195 Status
= ProcessOptions (MenuOption
, TRUE
, FileFormTagsHead
, NULL
, &OptionString
);
2200 ScreenOperation
= UiUp
;
2205 ScreenOperation
= UiDown
;
2209 if (gClassOfVfr
!= EFI_FRONT_PAGE_SUBCLASS
) {
2211 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_CHECKBOX_OP
&& !(MenuOption
->ThisTag
->GrayOut
)) {
2212 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2213 gST
->ConOut
->OutputString (gST
->ConOut
, MenuOption
->Description
);
2214 Selection
= MenuOption
;
2215 ScreenOperation
= UiSelect
;
2222 if (((Key
.ScanCode
== SCAN_F1
) && ((gFunctionKeySetting
& FUNCTION_ONE
) != FUNCTION_ONE
)) ||
2223 ((Key
.ScanCode
== SCAN_F2
) && ((gFunctionKeySetting
& FUNCTION_TWO
) != FUNCTION_TWO
)) ||
2224 ((Key
.ScanCode
== SCAN_F9
) && ((gFunctionKeySetting
& FUNCTION_NINE
) != FUNCTION_NINE
)) ||
2225 ((Key
.ScanCode
== SCAN_F10
) && ((gFunctionKeySetting
& FUNCTION_TEN
) != FUNCTION_TEN
))
2228 // If the function key has been disabled, just ignore the key.
2231 for (Index
= 0; Index
< sizeof (gScanCodeToOperation
) / sizeof (gScanCodeToOperation
[0]); Index
++) {
2232 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
2233 if ((Key
.ScanCode
== SCAN_F9
) || (Key
.ScanCode
== SCAN_F10
)) {
2235 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2238 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2247 case CfScreenOperation
:
2248 IfrBinary
= gBinaryDataHead
;
2251 // Advance to the Ifr we are using
2253 for (Index
= 0; Index
< gActiveIfr
; Index
++) {
2254 IfrBinary
= IfrBinary
->Next
;
2257 if (ScreenOperation
!= UiPrevious
&& ScreenOperation
!= UiReset
) {
2259 // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset
2260 // ignore the selection and go back to reading keys.
2262 if (IsListEmpty (&Menu
)) {
2263 ControlFlag
= CfReadKey
;
2267 // if there is nothing logical to place a cursor on, just move on to wait for a key.
2269 for (Link
= Menu
.ForwardLink
; Link
!= &Menu
; Link
= Link
->ForwardLink
) {
2270 NextMenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2271 if (!(NextMenuOption
->ThisTag
->GrayOut
) && (NextMenuOption
->ThisTag
->Operand
!= EFI_IFR_SUBTITLE_OP
)) {
2276 if (Link
== &Menu
) {
2277 ControlFlag
= CfPrepareToReadKey
;
2283 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
2286 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
2287 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
2294 ControlFlag
= CfCheckSelection
;
2296 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2298 if (MenuOption
!= NULL
) {
2299 if (!SelectionsAreValid (MenuOption
, FileFormTagsHead
)) {
2306 if (IsListEmpty (&gMenuList
)) {
2308 if (IsListEmpty (&Menu
)) {
2309 ControlFlag
= CfReadKey
;
2316 while (gMenuRefreshHead
!= NULL
) {
2317 OldMenuRefreshEntry
= gMenuRefreshHead
->Next
;
2319 FreePool (gMenuRefreshHead
);
2321 gMenuRefreshHead
= OldMenuRefreshEntry
;
2324 // Remove the Cached page entry, free and init the menus, flag Selection as jumping to previous page and a valid Tag
2327 UiRemoveMenuListEntry (MenuOption
, &Selection
);
2328 Selection
->Previous
= TRUE
;
2333 gActiveIfr
= Selection
->IfrNumber
;
2337 ControlFlag
= CfCheckSelection
;
2339 ExtractRequestedNvMap (FileFormTags
, MenuOption
->ThisTag
->VariableNumber
, &VariableDefinition
);
2342 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_TEXT_OP
&&
2343 !(MenuOption
->ThisTag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
)) ||
2344 (MenuOption
->ThisTag
->GrayOut
) ||
2345 (MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2346 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2352 UpdateKeyHelp (MenuOption
, TRUE
);
2353 Status
= ProcessOptions (MenuOption
, TRUE
, FileFormTagsHead
, PageData
, &OptionString
);
2355 if (EFI_ERROR (Status
)) {
2361 if (OptionString
!= NULL
) {
2362 PrintStringAt (LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ 1, MenuOption
->Row
, OptionString
);
2365 if (MenuOption
->ThisTag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
2366 Selection
= MenuOption
;
2369 if (Selection
== NULL
) {
2373 Location
= (UINT8
*) &PageData
->EntryCount
;
2376 // If not a goto, dump single piece of data, otherwise dump everything
2378 if (Selection
->ThisTag
->Operand
== EFI_IFR_REF_OP
) {
2380 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2382 if (!SelectionsAreValid (MenuOption
, FileFormTagsHead
)) {
2388 UiAddMenuListEntry (Selection
);
2389 gPriorMenuEntry
= 0;
2392 // Now that we added a menu entry specific to a goto, we can always go back when someone hits the UiPrevious
2394 UiMenuList
= CR (gMenuList
.ForwardLink
, UI_MENU_LIST
, MenuLink
, UI_MENU_LIST_SIGNATURE
);
2395 UiMenuList
->FormerEntryNumber
= MenuOption
->EntryNumber
;
2400 // Rewind to the beginning of the menu
2402 for (; NewPos
->BackLink
!= &Menu
; NewPos
= NewPos
->BackLink
)
2406 // Get Total Count of Menu entries
2408 for (Count
= 1; NewPos
->ForwardLink
!= &Menu
; NewPos
= NewPos
->ForwardLink
) {
2412 // Rewind to the beginning of the menu
2414 for (; NewPos
->BackLink
!= &Menu
; NewPos
= NewPos
->BackLink
)
2418 // Copy the number of entries being described to the PageData location
2420 CopyMem (&Location
[0], &Count
, sizeof (UINT32
));
2422 for (Index
= 4; NewPos
->ForwardLink
!= &Menu
; Index
= Index
+ MenuOption
->ThisTag
->StorageWidth
+ 2) {
2424 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2425 Location
[Index
] = MenuOption
->ThisTag
->Operand
;
2426 Location
[Index
+ 1] = (UINT8
) (MenuOption
->ThisTag
->StorageWidth
+ 4);
2428 &Location
[Index
+ 4],
2429 &VariableDefinition
->NvRamMap
[MenuOption
->ThisTag
->StorageStart
],
2430 MenuOption
->ThisTag
->StorageWidth
2432 NewPos
= NewPos
->ForwardLink
;
2436 gPriorMenuEntry
= MenuOption
->EntryNumber
;
2441 // Copy the number of entries being described to the PageData location
2443 CopyMem (&Location
[0], &Count
, sizeof (UINT32
));
2446 // Start at PageData[4] since the EntryCount is a UINT32
2451 // Copy data to destination
2453 Location
[Index
] = MenuOption
->ThisTag
->Operand
;
2454 Location
[Index
+ 1] = (UINT8
) (MenuOption
->ThisTag
->StorageWidth
+ 4);
2456 &Location
[Index
+ 4],
2457 &VariableDefinition
->NvRamMap
[MenuOption
->ThisTag
->StorageStart
],
2458 MenuOption
->ThisTag
->StorageWidth
2465 ControlFlag
= CfCheckSelection
;
2467 if (gClassOfVfr
== EFI_FRONT_PAGE_SUBCLASS
) {
2471 // If NV flag is up, prompt user
2473 if (gNvUpdateRequired
) {
2474 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2476 YesResponse
= gYesResponse
[0];
2477 NoResponse
= gNoResponse
[0];
2480 CreateDialog (3, TRUE
, 0, NULL
, &Key
, gEmptyString
, gAreYouSure
, gEmptyString
);
2483 (Key
.ScanCode
!= SCAN_ESC
) &&
2484 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (NoResponse
| UPPER_LOWER_CASE_OFFSET
)) &&
2485 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (YesResponse
| UPPER_LOWER_CASE_OFFSET
))
2489 // If the user hits the YesResponse key
2491 if ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) == (YesResponse
| UPPER_LOWER_CASE_OFFSET
)) {
2499 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2501 if (MenuOption
!= NULL
) {
2502 if (!SelectionsAreValid (MenuOption
, FileFormTagsHead
)) {
2510 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
2511 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
2515 gST
->ConOut
->ClearScreen (gST
->ConOut
);
2519 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->Flags
, FALSE
);
2520 UpdateStatusBar (NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->Flags
, FALSE
);
2522 if (IfrBinary
->UnRegisterOnExit
) {
2523 Hii
->RemovePack (Hii
, MenuOption
->Handle
);
2529 // Clean up the allocated data buffers
2531 FreeData (FileFormTagsHead
, FormattedString
, OptionString
);
2533 gST
->ConOut
->ClearScreen (gST
->ConOut
);
2537 ControlFlag
= CfCheckSelection
;
2538 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2539 if (MenuOption
->Skip
== 1) {
2541 // In the tail of the Date/Time op-code set, go left.
2543 NewPos
= NewPos
->BackLink
;
2546 // In the middle of the Data/Time op-code set, go left.
2548 NextMenuOption
= CR (NewPos
->ForwardLink
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2549 if (NextMenuOption
->Skip
== 1) {
2550 NewPos
= NewPos
->BackLink
;
2557 ControlFlag
= CfCheckSelection
;
2558 if ((MenuOption
->Skip
== 0) &&
2559 ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
))
2562 // We are in the head or middle of the Date/Time op-code set, advance right.
2564 NewPos
= NewPos
->ForwardLink
;
2569 ControlFlag
= CfCheckSelection
;
2571 if (NewPos
->BackLink
!= &Menu
) {
2574 // Adjust Date/Time position before we advance forward.
2576 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2579 // Caution that we have already rewind to the top, don't go backward in this situation.
2581 if (NewPos
->BackLink
!= &Menu
) {
2582 NewPos
= NewPos
->BackLink
;
2585 PreviousMenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2588 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended
2589 // to be one that back to the previous set of op-codes, we need to advance to the sencond
2590 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
2591 // checking can be done.
2593 DataAndTimeLineNumberPad
= AdjustDateAndTimePosition (TRUE
, &NewPos
);
2597 // If the previous MenuOption contains a display-only op-code, skip to the next one
2599 if (PreviousMenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| PreviousMenuOption
->ThisTag
->GrayOut
) {
2601 // This is ok as long as not at the end of the list
2603 if (NewPos
->BackLink
== &Menu
) {
2605 // If we are at the start of the list, then this list must start with a display only
2606 // piece of data, so do not allow the backward motion
2608 ScreenOperation
= UiDown
;
2610 if (PreviousMenuOption
->Row
<= TopRow
) {
2611 if (TopOfScreen
->BackLink
!= &Menu
) {
2612 TopOfScreen
= TopOfScreen
->BackLink
;
2617 UpdateStatusBar (INPUT_ERROR
, PreviousMenuOption
->ThisTag
->Flags
, FALSE
);
2623 // Check the previous menu entry to see if it was a zero-length advance. If it was,
2624 // don't worry about a redraw.
2626 if ((MenuOption
->Row
- PreviousMenuOption
->Skip
- DataAndTimeLineNumberPad
< TopRow
) ||
2627 (PreviousMenuOption
->Skip
> MenuOption
->Row
)
2630 if (TopOfScreen
->BackLink
== &Menu
) {
2637 // Is the current top of screen a zero-advance op-code?
2638 // If so, keep moving forward till we hit a >0 advance op-code
2640 SavedMenuOption
= CR (TopOfScreen
->BackLink
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2641 TopOfScreen
= TopOfScreen
->BackLink
;
2642 } while (SavedMenuOption
->Skip
== 0);
2644 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2646 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2649 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->Flags
, FALSE
);
2652 SavedMenuOption
= MenuOption
;
2653 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2654 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| MenuOption
->ThisTag
->GrayOut
) {
2656 // If we are at the end of the list and sitting on a text op, we need to more forward
2658 ScreenOperation
= UiDown
;
2659 ControlFlag
= CfScreenOperation
;
2663 MenuOption
= SavedMenuOption
;
2669 ControlFlag
= CfCheckSelection
;
2671 SavedListEntry
= NewPos
;
2673 for (Index
= BottomRow
; Index
>= TopRow
+ 1; Index
-= MenuOption
->Skip
) {
2674 if (Link
->BackLink
== &Menu
) {
2676 Link
= SavedListEntry
;
2677 MenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2683 Link
= Link
->BackLink
;
2684 MenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2686 SavedListEntry
= Link
;
2692 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2693 // Don't do this when we are already in the first page.
2696 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2697 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2698 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2703 ControlFlag
= CfCheckSelection
;
2705 SavedListEntry
= NewPos
;
2707 NewPos
= TopOfScreen
;
2708 for (Index
= TopRow
; Index
<= BottomRow
- 1; Index
+= MenuOption
->Skip
) {
2709 if (NewPos
->ForwardLink
== &Menu
) {
2710 NewPos
= SavedListEntry
;
2711 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2720 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2721 NewPos
= NewPos
->ForwardLink
;
2728 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2729 // Don't do this when we are already in the last page.
2732 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2733 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2734 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2739 ControlFlag
= CfCheckSelection
;
2741 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
2742 // to be one that progresses to the next set of op-codes, we need to advance to the last
2743 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
2744 // checking can be done. The only other logic we need to introduce is that if a Date/Time
2745 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
2746 // the Date/Time op-code.
2748 DataAndTimeLineNumberPad
= AdjustDateAndTimePosition (FALSE
, &NewPos
);
2750 if (NewPos
->ForwardLink
!= &Menu
) {
2752 NewPos
= NewPos
->ForwardLink
;
2753 NextMenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2757 // If the next MenuOption contains a display-only op-code, skip to the next one
2758 // Also if the next MenuOption is date or time,
2760 if (NextMenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| NextMenuOption
->ThisTag
->GrayOut
) {
2762 // This is ok as long as not at the end of the list
2764 if (NewPos
== &Menu
) {
2766 // If we are at the end of the list, then this list must end with a display only
2767 // piece of data, so do not allow the forward motion
2769 UpdateStatusBar (INPUT_ERROR
, NextMenuOption
->ThisTag
->Flags
, FALSE
);
2770 NewPos
= NewPos
->BackLink
;
2771 ScreenOperation
= UiUp
;
2777 // An option might be multi-line, so we need to reflect that data in the overall skip value
2779 UpdateOptionSkipLines (PageData
, NextMenuOption
, FileFormTagsHead
, &OptionString
, SkipValue
);
2781 if (NextMenuOption
->Skip
> 1) {
2782 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ NextMenuOption
->Skip
- 1;
2784 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DataAndTimeLineNumberPad
;
2787 // If we are going to scroll
2789 if (Temp
> BottomRow
) {
2792 // Is the current top of screen a zero-advance op-code?
2793 // If so, keep moving forward till we hit a >0 advance op-code
2795 SavedMenuOption
= CR (TopOfScreen
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2798 // If bottom op-code is more than one line or top op-code is more than one line
2800 if ((NextMenuOption
->Skip
> 1) || (MenuOption
->Skip
> 1)) {
2802 // Is the bottom op-code greater than or equal in size to the top op-code?
2804 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- OldSkipValue
)) {
2806 // Skip the top op-code
2808 TopOfScreen
= TopOfScreen
->ForwardLink
;
2809 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- OldSkipValue
);
2811 OldSkipValue
= Difference
;
2813 SavedMenuOption
= CR (TopOfScreen
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2816 // If we have a remainder, skip that many more op-codes until we drain the remainder
2819 Difference
>= (INTN
) SavedMenuOption
->Skip
;
2820 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
2823 // Since the Difference is greater than or equal to this op-code's skip value, skip it
2825 TopOfScreen
= TopOfScreen
->ForwardLink
;
2826 SavedMenuOption
= CR (TopOfScreen
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2827 if (Difference
< (INTN
) SavedMenuOption
->Skip
) {
2828 Difference
= SavedMenuOption
->Skip
- Difference
- 1;
2831 if (Difference
== (INTN
) SavedMenuOption
->Skip
) {
2832 TopOfScreen
= TopOfScreen
->ForwardLink
;
2833 SavedMenuOption
= CR (TopOfScreen
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2834 Difference
= SavedMenuOption
->Skip
- Difference
;
2840 // Since we will act on this op-code in the next routine, and increment the
2841 // SkipValue, set the skips to one less than what is required.
2843 SkipValue
= Difference
- 1;
2847 // Since we will act on this op-code in the next routine, and increment the
2848 // SkipValue, set the skips to one less than what is required.
2850 SkipValue
= OldSkipValue
+ (Temp
- BottomRow
) - 1;
2853 if ((OldSkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
2854 TopOfScreen
= TopOfScreen
->ForwardLink
;
2857 SkipValue
= OldSkipValue
;
2861 // If the op-code at the top of the screen is more than one line, let's not skip it yet
2862 // Let's set a skip flag to smoothly scroll the top of the screen.
2864 if (SavedMenuOption
->Skip
> 1) {
2865 if (SavedMenuOption
== NextMenuOption
) {
2872 TopOfScreen
= TopOfScreen
->ForwardLink
;
2874 } while (SavedMenuOption
->Skip
== 0);
2877 OldSkipValue
= SkipValue
;
2880 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->Flags
, FALSE
);
2884 SavedMenuOption
= MenuOption
;
2885 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2886 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| MenuOption
->ThisTag
->GrayOut
) {
2888 // If we are at the end of the list and sitting on a text op, we need to more forward
2890 ScreenOperation
= UiUp
;
2891 ControlFlag
= CfScreenOperation
;
2895 MenuOption
= SavedMenuOption
;
2897 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
2899 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2905 ControlFlag
= CfCheckSelection
;
2907 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2909 if (MenuOption
!= NULL
) {
2910 if (!SelectionsAreValid (MenuOption
, FileFormTagsHead
)) {
2917 // If callbacks are active, and the callback has a Write method, try to use it
2919 if (FileFormTags
->VariableDefinitions
->VariableName
== NULL
) {
2920 if ((FormCallback
!= NULL
) && (FormCallback
->NvWrite
!= NULL
)) {
2921 Status
= FormCallback
->NvWrite (
2923 (CHAR16
*) L
"Setup",
2924 &FileFormTags
->FormTags
.Tags
[0].GuidValue
,
2925 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2926 VariableDefinition
->VariableSize
,
2927 (VOID
*) VariableDefinition
->NvRamMap
,
2932 Status
= gRT
->SetVariable (
2933 (CHAR16
*) L
"Setup",
2934 &FileFormTags
->FormTags
.Tags
[0].GuidValue
,
2935 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2936 VariableDefinition
->VariableSize
,
2937 (VOID
*) VariableDefinition
->NvRamMap
2941 VariableDefinition
= FileFormTags
->VariableDefinitions
;
2943 for (; VariableDefinition
!= NULL
; VariableDefinition
= VariableDefinition
->Next
) {
2944 if ((FormCallback
!= NULL
) && (FormCallback
->NvWrite
!= NULL
)) {
2945 Status
= FormCallback
->NvWrite (
2947 VariableDefinition
->VariableName
,
2948 &VariableDefinition
->Guid
,
2949 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2950 VariableDefinition
->VariableSize
,
2951 (VOID
*) VariableDefinition
->NvRamMap
,
2956 Status
= gRT
->SetVariable (
2957 VariableDefinition
->VariableName
,
2958 &VariableDefinition
->Guid
,
2959 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2960 VariableDefinition
->VariableSize
,
2961 (VOID
*) VariableDefinition
->NvRamMap
2967 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->Flags
, FALSE
);
2968 UpdateStatusBar (NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->Flags
, FALSE
);
2972 ControlFlag
= CfCheckSelection
;
2974 NvMapListHead
= NULL
;
2976 Status
= Hii
->GetDefaultImage (Hii
, MenuOption
->Handle
, EFI_IFR_FLAG_DEFAULT
, &NvMapListHead
);
2978 if (!EFI_ERROR (Status
)) {
2979 ASSERT_EFI_ERROR (NULL
!= NvMapListHead
);
2981 NvMapListNode
= NvMapListHead
;
2983 while (NULL
!= NvMapListNode
) {
2984 if (FileFormTags
->VariableDefinitions
->VariableId
== NvMapListNode
->VariablePack
->VariableId
) {
2985 NvMap
= (VOID
*) ((CHAR8
*) NvMapListNode
->VariablePack
+ sizeof (EFI_HII_VARIABLE_PACK
) + NvMapListNode
->VariablePack
->VariableNameLength
);
2986 NvMapSize
= NvMapListNode
->VariablePack
->Header
.Length
- sizeof (EFI_HII_VARIABLE_PACK
) - NvMapListNode
->VariablePack
->VariableNameLength
;
2989 NvMapListNode
= NvMapListNode
->NextVariablePack
;
2993 // Free the buffer that was allocated.
2995 FreePool (FileFormTags
->VariableDefinitions
->NvRamMap
);
2996 FreePool (FileFormTags
->VariableDefinitions
->FakeNvRamMap
);
2999 // Allocate, copy the NvRamMap.
3001 FileFormTags
->VariableDefinitions
->VariableFakeSize
= (UINT16
) (FileFormTags
->VariableDefinitions
->VariableFakeSize
- FileFormTags
->VariableDefinitions
->VariableSize
);
3002 FileFormTags
->VariableDefinitions
->VariableSize
= (UINT16
) NvMapSize
;
3003 FileFormTags
->VariableDefinitions
->VariableFakeSize
= (UINT16
) (FileFormTags
->VariableDefinitions
->VariableFakeSize
+ FileFormTags
->VariableDefinitions
->VariableSize
);
3005 FileFormTags
->VariableDefinitions
->NvRamMap
= AllocateZeroPool (FileFormTags
->VariableDefinitions
->VariableSize
);
3006 ASSERT (FileFormTags
->VariableDefinitions
->NvRamMap
!= NULL
);
3008 FileFormTags
->VariableDefinitions
->FakeNvRamMap
= AllocateZeroPool (NvMapSize
+ FileFormTags
->VariableDefinitions
->VariableFakeSize
);
3009 ASSERT (FileFormTags
->VariableDefinitions
->FakeNvRamMap
!= NULL
);
3011 CopyMem (FileFormTags
->VariableDefinitions
->NvRamMap
, NvMap
, NvMapSize
);
3012 FreePool (NvMapListHead
);
3015 UpdateStatusBar (NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->Flags
, TRUE
);
3018 // After the repaint operation, we should refresh the highlight.
3023 case CfUiNoOperation
:
3024 ControlFlag
= CfCheckSelection
;
3028 while (gMenuRefreshHead
!= NULL
) {
3029 OldMenuRefreshEntry
= gMenuRefreshHead
->Next
;
3031 FreePool (gMenuRefreshHead
);
3033 gMenuRefreshHead
= OldMenuRefreshEntry
;
3036 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, Row
+ 4);
3037 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
3038 gST
->ConOut
->OutputString (gST
->ConOut
, (CHAR16
*) L
"\n");
3040 gActiveIfr
= MenuOption
->IfrNumber
;
3051 IN BOOLEAN Direction
,
3052 IN LIST_ENTRY
*CurrentPos
3056 Routine Description:
3057 Determine if the menu is the last menu that can be selected.
3060 Direction - the scroll direction. False is down. True is up.
3063 FALSE -- the menu isn't the last menu that can be selected.
3064 TRUE -- the menu is the last menu that can be selected.
3068 UI_MENU_OPTION
*MenuOption
;
3071 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
3073 if (Temp
== &Menu
) {
3077 for (; Temp
!= &Menu
; Temp
= Direction
? Temp
->BackLink
: Temp
->ForwardLink
) {
3078 MenuOption
= CR (Temp
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
3079 if (!(MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| MenuOption
->ThisTag
->GrayOut
)) {
3088 AdjustDateAndTimePosition (
3089 IN BOOLEAN DirectionUp
,
3090 IN LIST_ENTRY
**CurrentPosition
3093 Routine Description:
3094 Adjust Data and Time tag position accordingly.
3095 Data format : [01/02/2004] [11:22:33]
3096 Line number : 0 0 1 0 0 1
3099 Direction - the up or down direction. False is down. True is up.
3100 CurrentPos - Current position.
3103 Return line number to pad. It is possible that we stand on a zero-advance
3104 data or time opcode, so pad one line when we judge if we are going to scroll outside.
3108 LIST_ENTRY
*NewPosition
;
3109 UI_MENU_OPTION
*MenuOption
;
3110 UINTN PadLineNumber
;
3113 NewPosition
= *CurrentPosition
;
3114 MenuOption
= CR (NewPosition
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
3116 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
3118 // Calculate the distance from current position to the last Date/Time op-code.
3121 while (MenuOption
->ThisTag
->NumberOfLines
== 0) {
3123 NewPosition
= NewPosition
->ForwardLink
;
3124 MenuOption
= CR (NewPosition
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
3128 NewPosition
= *CurrentPosition
;
3131 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended
3132 // to be one that back to the previous set of op-codes, we need to advance to the first
3133 // Date/Time op-code and leave the remaining logic in CfUiUp intact so the appropriate
3134 // checking can be done.
3136 while (Count
++ < 2) {
3137 NewPosition
= NewPosition
->BackLink
;
3141 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
3142 // to be one that progresses to the next set of op-codes, we need to advance to the last
3143 // Date/Time op-code and leave the remaining logic in CfUiDown intact so the appropriate
3144 // checking can be done.
3146 while (Count
-- > 0) {
3147 NewPosition
= NewPosition
->ForwardLink
;
3151 *CurrentPosition
= NewPosition
;
3154 return PadLineNumber
;