]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/SetupBrowserDxe/Ui.c
Modules clean up.
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / SetupBrowserDxe / Ui.c
1 /**@file
2 Implementation for UI.
3
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
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15
16 #include "Setup.h"
17 #include "Ui.h"
18 #include "Colors.h"
19
20 //
21 // Implementation
22 //
23 VOID
24 SetUnicodeMem (
25 IN VOID *Buffer,
26 IN UINTN Size,
27 IN CHAR16 Value
28 )
29 /*++
30
31 Routine Description:
32
33 Set Buffer to Value for Size bytes.
34
35 Arguments:
36
37 Buffer - Memory to set.
38
39 Size - Number of bytes to set
40
41 Value - Value of the set operation.
42
43 Returns:
44
45 None
46
47 --*/
48 {
49 CHAR16 *Ptr;
50
51 Ptr = Buffer;
52 while (Size--) {
53 *(Ptr++) = Value;
54 }
55 }
56
57 VOID
58 UiInitMenu (
59 VOID
60 )
61 /*++
62
63 Routine Description:
64 Initialize Menu option list.
65
66 Arguments:
67
68 Returns:
69
70 --*/
71 {
72 InitializeListHead (&Menu);
73 }
74
75 VOID
76 UiInitMenuList (
77 VOID
78 )
79 /*++
80
81 Routine Description:
82 Initialize Menu option list.
83
84 Arguments:
85
86 Returns:
87
88 --*/
89 {
90 InitializeListHead (&gMenuList);
91 }
92
93 VOID
94 UiRemoveMenuListEntry (
95 IN UI_MENU_OPTION *Selection,
96 OUT UI_MENU_OPTION **PreviousSelection
97 )
98 /*++
99
100 Routine Description:
101 Remove Menu option list.
102
103 Arguments:
104
105 Returns:
106
107 --*/
108 {
109 UI_MENU_LIST *UiMenuList;
110
111 *PreviousSelection = AllocateZeroPool (sizeof (UI_MENU_OPTION));
112 ASSERT (*PreviousSelection != NULL);
113
114 if (!IsListEmpty (&gMenuList)) {
115 UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);
116 (*PreviousSelection)->IfrNumber = UiMenuList->Selection.IfrNumber;
117 (*PreviousSelection)->FormId = UiMenuList->Selection.FormId;
118 (*PreviousSelection)->Tags = UiMenuList->Selection.Tags;
119 (*PreviousSelection)->ThisTag = UiMenuList->Selection.ThisTag;
120 (*PreviousSelection)->Handle = UiMenuList->Selection.Handle;
121 gEntryNumber = UiMenuList->FormerEntryNumber;
122 RemoveEntryList (&UiMenuList->MenuLink);
123 FreePool (UiMenuList);
124 }
125 }
126
127 VOID
128 UiFreeMenuList (
129 VOID
130 )
131 /*++
132
133 Routine Description:
134 Free Menu option linked list.
135
136 Arguments:
137
138 Returns:
139
140 --*/
141 {
142 UI_MENU_LIST *UiMenuList;
143
144 while (!IsListEmpty (&gMenuList)) {
145 UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);
146 RemoveEntryList (&UiMenuList->MenuLink);
147 FreePool (UiMenuList);
148 }
149 }
150
151 VOID
152 UiAddMenuListEntry (
153 IN UI_MENU_OPTION *Selection
154 )
155 /*++
156
157 Routine Description:
158 Add one menu entry to the linked lst
159
160 Arguments:
161
162 Returns:
163
164 --*/
165 {
166 UI_MENU_LIST *UiMenuList;
167
168 UiMenuList = AllocateZeroPool (sizeof (UI_MENU_LIST));
169 ASSERT (UiMenuList != NULL);
170
171 UiMenuList->Signature = UI_MENU_LIST_SIGNATURE;
172 CopyMem (&UiMenuList->Selection, Selection, sizeof (UI_MENU_OPTION));
173
174 InsertHeadList (&gMenuList, &UiMenuList->MenuLink);
175 }
176
177 VOID
178 UiFreeMenu (
179 VOID
180 )
181 /*++
182
183 Routine Description:
184 Free Menu option linked list.
185
186 Arguments:
187
188 Returns:
189
190 --*/
191 {
192 UI_MENU_OPTION *MenuOption;
193
194 while (!IsListEmpty (&Menu)) {
195 MenuOption = CR (Menu.ForwardLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
196 RemoveEntryList (&MenuOption->Link);
197
198 //
199 // We allocated space for this description when we did a GetToken, free it here
200 //
201 FreePool (MenuOption->Description);
202 FreePool (MenuOption);
203 }
204 }
205
206 STATIC
207 VOID
208 UpdateDateAndTime (
209 VOID
210 )
211 /*++
212
213 Routine Description:
214 Refresh screen with current date and/or time based on screen context
215
216 Arguments:
217
218 Returns:
219
220 --*/
221 {
222 CHAR16 *OptionString;
223 MENU_REFRESH_ENTRY *MenuRefreshEntry;
224 UINTN Index;
225 UINTN Loop;
226
227 OptionString = NULL;
228
229 if (gMenuRefreshHead != NULL) {
230
231 MenuRefreshEntry = gMenuRefreshHead;
232
233 do {
234 gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute);
235 ProcessOptions (MenuRefreshEntry->MenuOption, FALSE, MenuRefreshEntry->FileFormTagsHead, NULL, &OptionString);
236
237 if (OptionString != NULL) {
238 //
239 // If leading spaces on OptionString - remove the spaces
240 //
241 for (Index = 0; OptionString[Index] == L' '; Index++)
242 ;
243
244 for (Loop = 0; OptionString[Index] != CHAR_NULL; Index++) {
245 OptionString[Loop] = OptionString[Index];
246 Loop++;
247 }
248
249 OptionString[Loop] = CHAR_NULL;
250
251 PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, OptionString);
252 }
253
254 MenuRefreshEntry = MenuRefreshEntry->Next;
255
256 } while (MenuRefreshEntry != NULL);
257 }
258
259 if (OptionString != NULL) {
260 FreePool (OptionString);
261 }
262 }
263
264 EFI_STATUS
265 UiWaitForSingleEvent (
266 IN EFI_EVENT Event,
267 IN UINT64 Timeout OPTIONAL
268 )
269 /*++
270
271 Routine Description:
272 Wait for a given event to fire, or for an optional timeout to expire.
273
274 Arguments:
275 Event - The event to wait for
276
277 Timeout - An optional timeout value in 100 ns units.
278
279 Returns:
280
281 EFI_SUCCESS - Event fired before Timeout expired.
282 EFI_TIME_OUT - Timout expired before Event fired.
283
284 --*/
285 {
286 EFI_STATUS Status;
287 UINTN Index;
288 EFI_EVENT TimerEvent;
289 EFI_EVENT WaitList[2];
290
291 if (Timeout) {
292 //
293 // Create a timer event
294 //
295 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
296 if (!EFI_ERROR (Status)) {
297 //
298 // Set the timer event
299 //
300 gBS->SetTimer (
301 TimerEvent,
302 TimerRelative,
303 Timeout
304 );
305
306 //
307 // Wait for the original event or the timer
308 //
309 WaitList[0] = Event;
310 WaitList[1] = TimerEvent;
311 Status = gBS->WaitForEvent (2, WaitList, &Index);
312 gBS->CloseEvent (TimerEvent);
313
314 //
315 // If the timer expired, change the return to timed out
316 //
317 if (!EFI_ERROR (Status) && Index == 1) {
318 Status = EFI_TIMEOUT;
319 }
320 }
321 } else {
322 //
323 // Update screen every second
324 //
325 Timeout = ONE_SECOND;
326
327 do {
328 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
329
330 //
331 // Set the timer event
332 //
333 gBS->SetTimer (
334 TimerEvent,
335 TimerRelative,
336 Timeout
337 );
338
339 //
340 // Wait for the original event or the timer
341 //
342 WaitList[0] = Event;
343 WaitList[1] = TimerEvent;
344 Status = gBS->WaitForEvent (2, WaitList, &Index);
345
346 //
347 // If the timer expired, update anything that needs a refresh and keep waiting
348 //
349 if (!EFI_ERROR (Status) && Index == 1) {
350 Status = EFI_TIMEOUT;
351 UpdateDateAndTime ();
352 }
353
354 gBS->CloseEvent (TimerEvent);
355 } while (Status == EFI_TIMEOUT);
356 }
357
358 return Status;
359 }
360
361 VOID
362 UiAddMenuOption (
363 IN CHAR16 *String,
364 IN EFI_HII_HANDLE Handle,
365 IN EFI_TAG *Tags,
366 IN VOID *FormBinary,
367 IN UINTN IfrNumber
368 )
369 /*++
370
371 Routine Description:
372 Add one menu option by specified description and context.
373
374 Arguments:
375 String - String description for this option.
376 Context - Context data for entry.
377
378 Returns:
379
380 --*/
381 {
382 UI_MENU_OPTION *MenuOption;
383
384 MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));
385 ASSERT (MenuOption);
386
387 MenuOption->Signature = UI_MENU_OPTION_SIGNATURE;
388 MenuOption->Description = String;
389 MenuOption->Handle = Handle;
390 MenuOption->FormBinary = FormBinary;
391 MenuOption->IfrNumber = IfrNumber;
392 MenuOption->Skip = 1;
393 MenuOption->Tags = Tags;
394 MenuOption->TagIndex = 0;
395 MenuOption->ThisTag = &(MenuOption->Tags[MenuOption->TagIndex]);
396 MenuOption->EntryNumber = (UINT16) IfrNumber;
397
398 InsertTailList (&Menu, &MenuOption->Link);
399 }
400
401 VOID
402 UiAddSubMenuOption (
403 IN CHAR16 *String,
404 IN EFI_HII_HANDLE Handle,
405 IN EFI_TAG *Tags,
406 IN UINTN TagIndex,
407 IN UINT16 FormId,
408 IN UINT16 MenuItemCount
409 )
410 /*++
411
412 Routine Description:
413 Add one menu option by specified description and context.
414
415 Arguments:
416 String - String description for this option.
417 Context - Context data for entry.
418
419 Returns:
420
421 --*/
422 {
423 UI_MENU_OPTION *MenuOption;
424
425 MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));
426 ASSERT (MenuOption);
427
428 MenuOption->Signature = UI_MENU_OPTION_SIGNATURE;
429 MenuOption->Description = String;
430 MenuOption->Handle = Handle;
431 MenuOption->Skip = Tags[TagIndex].NumberOfLines;
432 MenuOption->IfrNumber = gActiveIfr;
433 MenuOption->Tags = Tags;
434 MenuOption->TagIndex = TagIndex;
435 MenuOption->ThisTag = &(MenuOption->Tags[MenuOption->TagIndex]);
436 MenuOption->Consistency = Tags[TagIndex].Consistency;
437 MenuOption->FormId = FormId;
438 MenuOption->GrayOut = Tags[TagIndex].GrayOut;
439 MenuOption->EntryNumber = MenuItemCount;
440
441 InsertTailList (&Menu, &MenuOption->Link);
442 }
443
444 EFI_STATUS
445 CreateDialog (
446 IN UINTN NumberOfLines,
447 IN BOOLEAN HotKey,
448 IN UINTN MaximumStringSize,
449 OUT CHAR16 *StringBuffer,
450 OUT EFI_INPUT_KEY *KeyValue,
451 IN CHAR16 *String,
452 ...
453 )
454 /*++
455
456 Routine Description:
457 Routine used to abstract a generic dialog interface and return the selected key or string
458
459 Arguments:
460 NumberOfLines - The number of lines for the dialog box
461 HotKey - Defines whether a single character is parsed (TRUE) and returned in KeyValue
462 or a string is returned in StringBuffer. Two special characters are considered when entering a string, a SCAN_ESC and
463 an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates string input and returns
464 MaximumStringSize - The maximum size in bytes of a typed in string (each character is a CHAR16) and the minimum string returned is two bytes
465 StringBuffer - The passed in pointer to the buffer which will hold the typed in string if HotKey is FALSE
466 KeyValue - The EFI_KEY value returned if HotKey is TRUE..
467 String - Pointer to the first string in the list
468 ... - A series of (quantity == NumberOfLines) text strings which will be used to construct the dialog box
469
470 Returns:
471 EFI_SUCCESS - Displayed dialog and received user interaction
472 EFI_INVALID_PARAMETER - One of the parameters was invalid (e.g. (StringBuffer == NULL) && (HotKey == FALSE))
473 EFI_DEVICE_ERROR - User typed in an ESC character to exit the routine
474
475 --*/
476 {
477 VA_LIST Marker;
478 UINTN Count;
479 EFI_INPUT_KEY Key;
480 UINTN LargestString;
481 CHAR16 *TempString;
482 CHAR16 *BufferedString;
483 CHAR16 *StackString;
484 CHAR16 KeyPad[2];
485 UINTN Start;
486 UINTN Top;
487 UINTN Index;
488 BOOLEAN SelectionComplete;
489 UINTN InputOffset;
490 UINTN CurrentAttribute;
491 UINTN DimensionsWidth;
492 UINTN DimensionsHeight;
493
494 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;
495 DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;
496
497 SelectionComplete = FALSE;
498 InputOffset = 0;
499 TempString = AllocateZeroPool (MaximumStringSize * 2);
500 BufferedString = AllocateZeroPool (MaximumStringSize * 2);
501 CurrentAttribute = gST->ConOut->Mode->Attribute;
502
503 ASSERT (TempString);
504 ASSERT (BufferedString);
505
506 VA_START (Marker, String);
507
508 //
509 // Zero the outgoing buffer
510 //
511 ZeroMem (StringBuffer, MaximumStringSize);
512
513 if (HotKey) {
514 if (KeyValue == NULL) {
515 return EFI_INVALID_PARAMETER;
516 }
517 } else {
518 if (StringBuffer == NULL) {
519 return EFI_INVALID_PARAMETER;
520 }
521 }
522 //
523 // Disable cursor
524 //
525 gST->ConOut->EnableCursor (gST->ConOut, FALSE);
526
527 LargestString = (GetStringWidth (String) / 2);
528
529 if (LargestString == L' ') {
530 InputOffset = 1;
531 }
532 //
533 // Determine the largest string in the dialog box
534 // Notice we are starting with 1 since String is the first string
535 //
536 for (Count = 1; Count < NumberOfLines; Count++) {
537 StackString = VA_ARG (Marker, CHAR16 *);
538
539 if (StackString[0] == L' ') {
540 InputOffset = Count + 1;
541 }
542
543 if ((GetStringWidth (StackString) / 2) > LargestString) {
544 //
545 // Size of the string visually and subtract the width by one for the null-terminator
546 //
547 LargestString = (GetStringWidth (StackString) / 2);
548 }
549 }
550
551 Start = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1;
552 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1;
553
554 Count = 0;
555
556 //
557 // Display the Popup
558 //
559 CreateSharedPopUp (LargestString, NumberOfLines, &String);
560
561 //
562 // Take the first key typed and report it back?
563 //
564 if (HotKey) {
565 WaitForKeyStroke (&Key);
566 CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));
567
568 } else {
569 do {
570 WaitForKeyStroke (&Key);
571
572 switch (Key.UnicodeChar) {
573 case CHAR_NULL:
574 switch (Key.ScanCode) {
575 case SCAN_ESC:
576 FreePool (TempString);
577 FreePool (BufferedString);
578 gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);
579 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
580 return EFI_DEVICE_ERROR;
581
582 default:
583 break;
584 }
585
586 break;
587
588 case CHAR_CARRIAGE_RETURN:
589 SelectionComplete = TRUE;
590 FreePool (TempString);
591 FreePool (BufferedString);
592 gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);
593 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
594 return EFI_SUCCESS;
595 break;
596
597 case CHAR_BACKSPACE:
598 if (StringBuffer[0] != CHAR_NULL) {
599 for (Index = 0; StringBuffer[Index] != CHAR_NULL; Index++) {
600 TempString[Index] = StringBuffer[Index];
601 }
602 //
603 // Effectively truncate string by 1 character
604 //
605 TempString[Index - 1] = CHAR_NULL;
606 StrCpy (StringBuffer, TempString);
607 }
608
609 default:
610 //
611 // If it is the beginning of the string, don't worry about checking maximum limits
612 //
613 if ((StringBuffer[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
614 StrnCpy (StringBuffer, &Key.UnicodeChar, 1);
615 StrnCpy (TempString, &Key.UnicodeChar, 1);
616 } else if ((GetStringWidth (StringBuffer) < MaximumStringSize) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
617 KeyPad[0] = Key.UnicodeChar;
618 KeyPad[1] = CHAR_NULL;
619 StrCat (StringBuffer, KeyPad);
620 StrCat (TempString, KeyPad);
621 }
622 //
623 // If the width of the input string is now larger than the screen, we nee to
624 // adjust the index to start printing portions of the string
625 //
626 SetUnicodeMem (BufferedString, LargestString, L' ');
627
628 PrintStringAt (Start + 1, Top + InputOffset, BufferedString);
629
630 if ((GetStringWidth (StringBuffer) / 2) > (DimensionsWidth - 2)) {
631 Index = (GetStringWidth (StringBuffer) / 2) - DimensionsWidth + 2;
632 } else {
633 Index = 0;
634 }
635
636 for (Count = 0; Index + 1 < GetStringWidth (StringBuffer) / 2; Index++, Count++) {
637 BufferedString[Count] = StringBuffer[Index];
638 }
639
640 PrintStringAt (Start + 1, Top + InputOffset, BufferedString);
641 break;
642 }
643 } while (!SelectionComplete);
644 }
645
646 gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);
647 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
648 return EFI_SUCCESS;
649 }
650
651 VOID
652 CreateSharedPopUp (
653 IN UINTN RequestedWidth,
654 IN UINTN NumberOfLines,
655 IN CHAR16 **ArrayOfStrings
656 )
657 {
658 UINTN Index;
659 UINTN Count;
660 CHAR16 Character;
661 UINTN Start;
662 UINTN End;
663 UINTN Top;
664 UINTN Bottom;
665 CHAR16 *String;
666
667 UINTN DimensionsWidth;
668 UINTN DimensionsHeight;
669
670 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;
671 DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;
672
673 Count = 0;
674
675 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
676
677 if ((RequestedWidth + 2) > DimensionsWidth) {
678 RequestedWidth = DimensionsWidth - 2;
679 }
680 //
681 // Subtract the PopUp width from total Columns, allow for one space extra on
682 // each end plus a border.
683 //
684 Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gScreenDimensions.LeftColumn + 1;
685 End = Start + RequestedWidth + 1;
686
687 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1;
688 Bottom = Top + NumberOfLines + 2;
689
690 Character = (CHAR16) BOXDRAW_DOWN_RIGHT;
691 PrintCharAt (Start, Top, Character);
692 Character = (CHAR16) BOXDRAW_HORIZONTAL;
693 for (Index = Start; Index + 2 < End; Index++) {
694 PrintChar (Character);
695 }
696
697 Character = (CHAR16) BOXDRAW_DOWN_LEFT;
698 PrintChar (Character);
699 Character = (CHAR16) BOXDRAW_VERTICAL;
700 for (Index = Top; Index + 2 < Bottom; Index++) {
701 String = ArrayOfStrings[Count];
702 Count++;
703
704 //
705 // This will clear the background of the line - we never know who might have been
706 // here before us. This differs from the next clear in that it used the non-reverse
707 // video for normal printing.
708 //
709 if (GetStringWidth (String) / 2 > 1) {
710 ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND);
711 }
712 //
713 // Passing in a space results in the assumption that this is where typing will occur
714 //
715 if (String[0] == L' ') {
716 ClearLines (Start + 1, End - 1, Index + 1, Index + 1, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND);
717 }
718 //
719 // Passing in a NULL results in a blank space
720 //
721 if (String[0] == CHAR_NULL) {
722 ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND);
723 }
724
725 PrintStringAt (
726 ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1,
727 Index + 1,
728 String
729 );
730 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
731 PrintCharAt (Start, Index + 1, Character);
732 PrintCharAt (End - 1, Index + 1, Character);
733 }
734
735 Character = (CHAR16) BOXDRAW_UP_RIGHT;
736 PrintCharAt (Start, Bottom - 1, Character);
737 Character = (CHAR16) BOXDRAW_HORIZONTAL;
738 for (Index = Start; Index + 2 < End; Index++) {
739 PrintChar (Character);
740 }
741
742 Character = (CHAR16) BOXDRAW_UP_LEFT;
743 PrintChar (Character);
744 }
745
746 VOID
747 CreatePopUp (
748 IN UINTN RequestedWidth,
749 IN UINTN NumberOfLines,
750 IN CHAR16 *ArrayOfStrings,
751 ...
752 )
753 {
754 CreateSharedPopUp (RequestedWidth, NumberOfLines, &ArrayOfStrings);
755 }
756
757 VOID
758 UpdateStatusBar (
759 IN UINTN MessageType,
760 IN UINT8 Flags,
761 IN BOOLEAN State
762 )
763 {
764 UINTN Index;
765 STATIC BOOLEAN InputError;
766 CHAR16 *NvUpdateMessage;
767 CHAR16 *InputErrorMessage;
768
769 NvUpdateMessage = GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), gHiiHandle);
770 InputErrorMessage = GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), gHiiHandle);
771
772 switch (MessageType) {
773 case INPUT_ERROR:
774 if (State) {
775 gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT);
776 PrintStringAt (
777 gScreenDimensions.LeftColumn + gPromptBlockWidth,
778 gScreenDimensions.BottomRow - 1,
779 InputErrorMessage
780 );
781 InputError = TRUE;
782 } else {
783 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);
784 for (Index = 0; Index < (GetStringWidth (InputErrorMessage) - 2) / 2; Index++) {
785 PrintAt (gScreenDimensions.LeftColumn + gPromptBlockWidth + Index, gScreenDimensions.BottomRow - 1, (CHAR16 *) L" ");
786 }
787
788 InputError = FALSE;
789 }
790 break;
791
792 case NV_UPDATE_REQUIRED:
793 if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {
794 if (State) {
795 gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT);
796 PrintStringAt (
797 gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth,
798 gScreenDimensions.BottomRow - 1,
799 NvUpdateMessage
800 );
801 gResetRequired = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED));
802
803 gNvUpdateRequired = TRUE;
804 } else {
805 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);
806 for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) {
807 PrintAt (
808 (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index),
809 gScreenDimensions.BottomRow - 1,
810 (CHAR16 *) L" "
811 );
812 }
813
814 gNvUpdateRequired = FALSE;
815 }
816 }
817 break;
818
819 case REFRESH_STATUS_BAR:
820 if (InputError) {
821 UpdateStatusBar (INPUT_ERROR, Flags, TRUE);
822 }
823
824 if (gNvUpdateRequired) {
825 UpdateStatusBar (NV_UPDATE_REQUIRED, Flags, TRUE);
826 }
827 break;
828
829 default:
830 break;
831 }
832
833 FreePool (InputErrorMessage);
834 FreePool (NvUpdateMessage);
835 return ;
836 }
837
838 VOID
839 FreeData (
840 IN EFI_FILE_FORM_TAGS *FileFormTagsHead,
841 IN CHAR16 *FormattedString,
842 IN CHAR16 *OptionString
843 )
844 /*++
845
846 Routine Description:
847
848 Used to remove the allocated data instances
849
850 Arguments:
851
852 Returns:
853
854 --*/
855 {
856 EFI_FILE_FORM_TAGS *FileForm;
857 EFI_FILE_FORM_TAGS *PreviousFileForm;
858 EFI_FORM_TAGS *FormTags;
859 EFI_FORM_TAGS *PreviousFormTags;
860 EFI_IFR_BINARY *IfrBinary;
861 EFI_IFR_BINARY *PreviousIfrBinary;
862 EFI_INCONSISTENCY_DATA *Inconsistent;
863 EFI_VARIABLE_DEFINITION *VariableDefinition;
864 EFI_VARIABLE_DEFINITION *PreviousVariableDefinition;
865 VOID *Buffer;
866 UINTN Index;
867
868 FileForm = FileFormTagsHead;
869
870 if (FormattedString != NULL) {
871 FreePool (FormattedString);
872 }
873
874 if (OptionString != NULL) {
875 FreePool (OptionString);
876 }
877
878 for (; FileForm != NULL;) {
879 PreviousFileForm = NULL;
880
881 //
882 // Advance FileForm to the last entry
883 //
884 for (; FileForm->NextFile != NULL; FileForm = FileForm->NextFile) {
885 PreviousFileForm = FileForm;
886 }
887
888 FormTags = &FileForm->FormTags;
889
890 for (; FormTags != NULL;) {
891 FormTags = &FileForm->FormTags;
892 PreviousFormTags = NULL;
893
894 //
895 // Advance FormTags to the last entry
896 //
897 for (; FormTags->Next != NULL; FormTags = FormTags->Next) {
898 PreviousFormTags = FormTags;
899 }
900 //
901 // Walk through each of the tags and free the IntList allocation
902 //
903 for (Index = 0; FormTags->Tags[Index].Operand != EFI_IFR_END_FORM_OP; Index++) {
904 //
905 // It is more than likely that the very last page will contain an end formset
906 //
907 if (FormTags->Tags[Index].Operand == EFI_IFR_END_FORM_SET_OP) {
908 break;
909 }
910
911 if (FormTags->Tags[Index].IntList != NULL) {
912 FreePool (FormTags->Tags[Index].IntList);
913 }
914 }
915
916 if (PreviousFormTags != NULL) {
917 FreePool (FormTags->Tags);
918 FormTags = PreviousFormTags;
919 FreePool (FormTags->Next);
920 FormTags->Next = NULL;
921 } else {
922 FreePool (FormTags->Tags);
923 FormTags = NULL;
924 }
925 }
926 //
927 // Last FileForm entry's Inconsistent database
928 //
929 Inconsistent = FileForm->InconsistentTags;
930
931 //
932 // Advance Inconsistent to the last entry
933 //
934 for (; Inconsistent->Next != NULL; Inconsistent = Inconsistent->Next)
935 ;
936
937 for (; Inconsistent != NULL;) {
938 //
939 // Preserve the Previous pointer
940 //
941 Buffer = (VOID *) Inconsistent->Previous;
942
943 //
944 // Free the current entry
945 //
946 FreePool (Inconsistent);
947
948 //
949 // Restore the Previous pointer
950 //
951 Inconsistent = (EFI_INCONSISTENCY_DATA *) Buffer;
952 }
953
954 VariableDefinition = FileForm->VariableDefinitions;
955
956 for (; VariableDefinition != NULL;) {
957 VariableDefinition = FileForm->VariableDefinitions;
958 PreviousVariableDefinition = NULL;
959
960 //
961 // Advance VariableDefinitions to the last entry
962 //
963 for (; VariableDefinition->Next != NULL; VariableDefinition = VariableDefinition->Next) {
964 PreviousVariableDefinition = VariableDefinition;
965 }
966
967 FreePool (VariableDefinition->VariableName);
968
969 if (VariableDefinition->NvRamMap != NULL) {
970 FreePool (VariableDefinition->NvRamMap);
971 }
972
973 if (VariableDefinition->FakeNvRamMap != NULL) {
974 FreePool (VariableDefinition->FakeNvRamMap);
975 }
976
977 if (PreviousVariableDefinition != NULL) {
978 VariableDefinition = PreviousVariableDefinition;
979 FreePool (VariableDefinition->Next);
980 VariableDefinition->Next = NULL;
981 } else {
982 FreePool (VariableDefinition);
983 VariableDefinition = NULL;
984 }
985 }
986
987 if (PreviousFileForm != NULL) {
988 FileForm = PreviousFileForm;
989 FreePool (FileForm->NextFile);
990 FileForm->NextFile = NULL;
991 } else {
992 FreePool (FileForm);
993 FileForm = NULL;
994 }
995 }
996
997 IfrBinary = gBinaryDataHead;
998
999 for (; IfrBinary != NULL;) {
1000 IfrBinary = gBinaryDataHead;
1001 PreviousIfrBinary = NULL;
1002
1003 //
1004 // Advance IfrBinary to the last entry
1005 //
1006 for (; IfrBinary->Next != NULL; IfrBinary = IfrBinary->Next) {
1007 PreviousIfrBinary = IfrBinary;
1008 }
1009
1010 FreePool (IfrBinary->IfrPackage);
1011
1012 if (PreviousIfrBinary != NULL) {
1013 IfrBinary = PreviousIfrBinary;
1014 FreePool (IfrBinary->Next);
1015 IfrBinary->Next = NULL;
1016 } else {
1017 FreePool (IfrBinary);
1018 IfrBinary = NULL;
1019 }
1020 }
1021
1022 FreePool (gPreviousValue);
1023 gPreviousValue = NULL;
1024
1025 //
1026 // Free Browser Strings
1027 //
1028 FreePool (gPressEnter);
1029 FreePool (gConfirmError);
1030 FreePool (gConfirmPassword);
1031 FreePool (gPromptForNewPassword);
1032 FreePool (gPromptForPassword);
1033 FreePool (gToggleCheckBox);
1034 FreePool (gNumericInput);
1035 FreePool (gMakeSelection);
1036 FreePool (gMoveHighlight);
1037 FreePool (gEscapeString);
1038 FreePool (gEnterCommitString);
1039 FreePool (gEnterString);
1040 FreePool (gFunctionOneString);
1041 FreePool (gFunctionTwoString);
1042 FreePool (gFunctionNineString);
1043 FreePool (gFunctionTenString);
1044 return ;
1045 }
1046
1047 STATIC
1048 BOOLEAN
1049 SelectionsAreValid (
1050 IN UI_MENU_OPTION *MenuOption,
1051 IN EFI_FILE_FORM_TAGS *FileFormTagsHead
1052 )
1053 /*++
1054
1055 Routine Description:
1056 Initiate late consistency checks against the current page.
1057
1058 Arguments:
1059 None
1060
1061 Returns:
1062
1063 --*/
1064 {
1065 LIST_ENTRY *Link;
1066 EFI_TAG *Tag;
1067 EFI_FILE_FORM_TAGS *FileFormTags;
1068 CHAR16 *StringPtr;
1069 CHAR16 NullCharacter;
1070 UINTN Index;
1071 UINT16 *NvRamMap;
1072 STRING_REF PopUp;
1073 EFI_INPUT_KEY Key;
1074 EFI_VARIABLE_DEFINITION *VariableDefinition;
1075
1076 StringPtr = (CHAR16 *) L"\0";
1077 NullCharacter = CHAR_NULL;
1078
1079 FileFormTags = FileFormTagsHead;
1080
1081 for (Index = 0; Index < MenuOption->IfrNumber; Index++) {
1082 FileFormTags = FileFormTags->NextFile;
1083 }
1084
1085 for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) {
1086 MenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
1087
1088 Tag = MenuOption->ThisTag;
1089
1090 ExtractRequestedNvMap (FileFormTags, Tag->VariableNumber, &VariableDefinition);
1091 NvRamMap = (UINT16 *) &VariableDefinition->NvRamMap[Tag->StorageStart];
1092
1093 //
1094 // If the op-code has a late check, ensure consistency checks are now applied
1095 //
1096 if (Tag->Flags & EFI_IFR_FLAG_LATE_CHECK) {
1097 if (ValueIsNotValid (TRUE, 0, Tag, FileFormTags, &PopUp)) {
1098 if (PopUp != 0x0000) {
1099 StringPtr = GetToken (PopUp, MenuOption->Handle);
1100
1101 CreatePopUp (GetStringWidth (StringPtr) / 2, 3, &NullCharacter, StringPtr, &NullCharacter);
1102
1103 do {
1104 WaitForKeyStroke (&Key);
1105
1106 switch (Key.UnicodeChar) {
1107
1108 case CHAR_CARRIAGE_RETURN:
1109 //
1110 // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
1111 //
1112 CopyMem (NvRamMap, &Tag->OldValue, Tag->StorageWidth);
1113 FreePool (StringPtr);
1114 break;
1115
1116 default:
1117 break;
1118 }
1119 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1120 }
1121
1122 return FALSE;
1123 }
1124 }
1125 }
1126
1127 return TRUE;
1128 }
1129
1130 UINT16
1131 GetWidth (
1132 IN EFI_TAG *Tag,
1133 IN EFI_HII_HANDLE Handle
1134 )
1135 /*++
1136
1137 Routine Description:
1138 Get the supported width for a particular op-code
1139
1140 Arguments:
1141 Tag - The Tag structure passed in.
1142 Handle - The handle in the HII database being used
1143
1144 Returns:
1145 Returns the number of CHAR16 characters that is support.
1146
1147
1148 --*/
1149 {
1150 CHAR16 *String;
1151 UINTN Size;
1152
1153 Size = 0x00;
1154
1155 //
1156 // See if the second text parameter is really NULL
1157 //
1158 if ((Tag->Operand == EFI_IFR_TEXT_OP) && (Tag->TextTwo != 0)) {
1159 String = GetToken (Tag->TextTwo, Handle);
1160 Size = StrLen (String);
1161 FreePool (String);
1162 }
1163
1164 if ((Tag->Operand == EFI_IFR_SUBTITLE_OP) ||
1165 (Tag->Operand == EFI_IFR_REF_OP) ||
1166 (Tag->Operand == EFI_IFR_PASSWORD_OP) ||
1167 (Tag->Operand == EFI_IFR_STRING_OP) ||
1168 (Tag->Operand == EFI_IFR_INVENTORY_OP) ||
1169 //
1170 // Allow a wide display if text op-code and no secondary text op-code
1171 //
1172 ((Tag->Operand == EFI_IFR_TEXT_OP) && (Size == 0x0000))
1173 ) {
1174 return (UINT16) (gPromptBlockWidth + gOptionBlockWidth);
1175 } else {
1176 return (UINT16) gPromptBlockWidth;
1177 }
1178 }
1179
1180 UINT16
1181 GetLineByWidth (
1182 IN CHAR16 *InputString,
1183 IN UINT16 LineWidth,
1184 IN OUT UINTN *Index,
1185 OUT CHAR16 **OutputString
1186 )
1187 /*++
1188
1189 Routine Description:
1190 Will copy LineWidth amount of a string in the OutputString buffer and return the
1191 number of CHAR16 characters that were copied into the OutputString buffer.
1192
1193 Arguments:
1194 InputString - String description for this option.
1195 LineWidth - Width of the desired string to extract in CHAR16 characters
1196 Index - Where in InputString to start the copy process
1197 OutputString - Buffer to copy the string into
1198
1199 Returns:
1200 Returns the number of CHAR16 characters that were copied into the OutputString buffer.
1201
1202
1203 --*/
1204 {
1205 static BOOLEAN Finished;
1206 UINT16 Count;
1207 UINT16 Count2;
1208
1209 if (Finished) {
1210 Finished = FALSE;
1211 return (UINT16) 0;
1212 }
1213
1214 Count = LineWidth;
1215 Count2 = 0;
1216
1217 *OutputString = AllocateZeroPool (((UINTN) (LineWidth + 1) * 2));
1218
1219 //
1220 // Ensure we have got a valid buffer
1221 //
1222 if (*OutputString != NULL) {
1223
1224 //
1225 //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.
1226 //To avoid displaying this empty line in screen, just skip the two CHARs here.
1227 //
1228 if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {
1229 *Index = *Index + 2;
1230 }
1231
1232 //
1233 // Fast-forward the string and see if there is a carriage-return in the string
1234 //
1235 for (; (InputString[*Index + Count2] != CHAR_CARRIAGE_RETURN) && (Count2 != LineWidth); Count2++)
1236 ;
1237
1238 //
1239 // Copy the desired LineWidth of data to the output buffer.
1240 // Also make sure that we don't copy more than the string.
1241 // Also make sure that if there are linefeeds, we account for them.
1242 //
1243 if ((StrSize (&InputString[*Index]) <= ((UINTN) (LineWidth + 1) * 2)) &&
1244 (StrSize (&InputString[*Index]) <= ((UINTN) (Count2 + 1) * 2))
1245 ) {
1246 //
1247 // Convert to CHAR16 value and show that we are done with this operation
1248 //
1249 LineWidth = (UINT16) ((StrSize (&InputString[*Index]) - 2) / 2);
1250 if (LineWidth != 0) {
1251 Finished = TRUE;
1252 }
1253 } else {
1254 if (Count2 == LineWidth) {
1255 //
1256 // Rewind the string from the maximum size until we see a space to break the line
1257 //
1258 for (; (InputString[*Index + LineWidth] != CHAR_SPACE) && (LineWidth != 0); LineWidth--)
1259 ;
1260 if (LineWidth == 0) {
1261 LineWidth = Count;
1262 }
1263 } else {
1264 LineWidth = Count2;
1265 }
1266 }
1267
1268 CopyMem (*OutputString, &InputString[*Index], LineWidth * 2);
1269
1270 //
1271 // If currently pointing to a space, increment the index to the first non-space character
1272 //
1273 for (;
1274 (InputString[*Index + LineWidth] == CHAR_SPACE) || (InputString[*Index + LineWidth] == CHAR_CARRIAGE_RETURN);
1275 (*Index)++
1276 )
1277 ;
1278 *Index = (UINT16) (*Index + LineWidth);
1279 return LineWidth;
1280 } else {
1281 return (UINT16) 0;
1282 }
1283 }
1284
1285 STATIC
1286 VOID
1287 UpdateOptionSkipLines (
1288 IN EFI_IFR_DATA_ARRAY *PageData,
1289 IN UI_MENU_OPTION *MenuOption,
1290 IN EFI_FILE_FORM_TAGS *FileFormTagsHead,
1291 IN CHAR16 **OptionalString,
1292 IN UINTN SkipValue
1293 )
1294 {
1295 UINTN Index;
1296 UINT16 Width;
1297 UINTN Row;
1298 UINTN OriginalRow;
1299 CHAR16 *OutputString;
1300 CHAR16 *OptionString;
1301
1302 Row = 0;
1303 OptionString = *OptionalString;
1304 OutputString = NULL;
1305
1306 ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);
1307
1308 if (OptionString != NULL) {
1309 Width = (UINT16) gOptionBlockWidth;
1310
1311 OriginalRow = Row;
1312
1313 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {
1314 //
1315 // If there is more string to process print on the next row and increment the Skip value
1316 //
1317 if (StrLen (&OptionString[Index])) {
1318 if (SkipValue == 0) {
1319 Row++;
1320 //
1321 // Since the Number of lines for this menu entry may or may not be reflected accurately
1322 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1323 // some testing to ensure we are keeping this in-sync.
1324 //
1325 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1326 //
1327 if ((Row - OriginalRow) >= MenuOption->Skip) {
1328 MenuOption->Skip++;
1329 }
1330 }
1331 }
1332
1333 FreePool (OutputString);
1334 if (SkipValue != 0) {
1335 SkipValue--;
1336 }
1337 }
1338
1339 Row = OriginalRow;
1340 }
1341
1342 *OptionalString = OptionString;
1343 }
1344 //
1345 // Search table for UiDisplayMenu()
1346 //
1347 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation[] = {
1348 { SCAN_UP, UiUp },
1349 { SCAN_DOWN, UiDown },
1350 { SCAN_PAGE_UP, UiPageUp },
1351 { SCAN_PAGE_DOWN, UiPageDown},
1352 { SCAN_ESC, UiReset},
1353 { SCAN_F2, UiPrevious},
1354 { SCAN_LEFT, UiLeft },
1355 { SCAN_RIGHT, UiRight },
1356 { SCAN_F9, UiDefault},
1357 { SCAN_F10, UiSave }
1358 };
1359
1360 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = {
1361 { UiNoOperation, CfUiNoOperation },
1362 { UiDefault, CfUiDefault },
1363 { UiSelect, CfUiSelect },
1364 { UiUp, CfUiUp},
1365 { UiDown, CfUiDown },
1366 { UiLeft, CfUiLeft },
1367 { UiRight, CfUiRight },
1368 { UiReset, CfUiReset },
1369 { UiSave, CfUiSave },
1370 { UiPrevious, CfUiPrevious },
1371 { UiPageUp, CfUiPageUp },
1372 { UiPageDown, CfUiPageDown }
1373 };
1374
1375 UI_MENU_OPTION *
1376 UiDisplayMenu (
1377 IN BOOLEAN SubMenu,
1378 IN EFI_FILE_FORM_TAGS *FileFormTagsHead,
1379 OUT EFI_IFR_DATA_ARRAY *PageData
1380 )
1381 /*++
1382
1383 Routine Description:
1384 Display menu and wait for user to select one menu option, then return it.
1385 If AutoBoot is enabled, then if user doesn't select any option,
1386 after period of time, it will automatically return the first menu option.
1387
1388 Arguments:
1389 SubMenu - Indicate is sub menu.
1390 FileFormTagsHead - A pointer to the EFI_FILE_FORM_TAGS structure.
1391 PageData - A pointer to the EFI_IFR_DATA_ARRAY.
1392
1393 Returns:
1394 Return the pointer of the menu which selected,
1395 otherwise return NULL.
1396
1397 --*/
1398 {
1399 INTN SkipValue;
1400 INTN Difference;
1401 INTN OldSkipValue;
1402 UINTN Row;
1403 UINTN Col;
1404 UINTN Temp;
1405 UINTN Temp2;
1406 UINTN TopRow;
1407 UINTN BottomRow;
1408 UINTN OriginalRow;
1409 UINTN Index;
1410 UINTN DataAndTimeLineNumberPad;
1411 UINT32 Count;
1412 INT16 OriginalTimeOut;
1413 UINT8 *Location;
1414 UINT16 Width;
1415 CHAR16 *StringPtr;
1416 CHAR16 *OptionString;
1417 CHAR16 *OutputString;
1418 CHAR16 *FormattedString;
1419 CHAR16 YesResponse;
1420 CHAR16 NoResponse;
1421 BOOLEAN NewLine;
1422 BOOLEAN Repaint;
1423 BOOLEAN SavedValue;
1424 EFI_STATUS Status;
1425 UI_MENU_LIST *UiMenuList;
1426 EFI_INPUT_KEY Key;
1427 LIST_ENTRY *Link;
1428 LIST_ENTRY *NewPos;
1429 LIST_ENTRY *TopOfScreen;
1430 LIST_ENTRY *SavedListEntry;
1431 UI_MENU_OPTION *Selection;
1432 UI_MENU_OPTION *MenuOption;
1433 UI_MENU_OPTION *NextMenuOption;
1434 UI_MENU_OPTION *SavedMenuOption;
1435 UI_MENU_OPTION *PreviousMenuOption;
1436 EFI_IFR_BINARY *IfrBinary;
1437 UI_CONTROL_FLAG ControlFlag;
1438 EFI_SCREEN_DESCRIPTOR LocalScreen;
1439 EFI_FILE_FORM_TAGS *FileFormTags;
1440 MENU_REFRESH_ENTRY *MenuRefreshEntry;
1441 MENU_REFRESH_ENTRY *OldMenuRefreshEntry;
1442 UI_SCREEN_OPERATION ScreenOperation;
1443 EFI_VARIABLE_DEFINITION *VariableDefinition;
1444 EFI_FORM_CALLBACK_PROTOCOL *FormCallback;
1445 EFI_HII_VARIABLE_PACK_LIST *NvMapListHead;
1446 EFI_HII_VARIABLE_PACK_LIST *NvMapListNode;
1447 VOID *NvMap;
1448 UINTN NvMapSize;
1449
1450 CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
1451
1452 VariableDefinition = NULL;
1453 Status = EFI_SUCCESS;
1454 FormattedString = NULL;
1455 OptionString = NULL;
1456 ScreenOperation = UiNoOperation;
1457 NewLine = TRUE;
1458 FormCallback = NULL;
1459 FileFormTags = NULL;
1460 OutputString = NULL;
1461 gUpArrow = FALSE;
1462 gDownArrow = FALSE;
1463 SkipValue = 0;
1464 OldSkipValue = 0;
1465 MenuRefreshEntry = gMenuRefreshHead;
1466 OldMenuRefreshEntry = gMenuRefreshHead;
1467 NextMenuOption = NULL;
1468 PreviousMenuOption = NULL;
1469 SavedMenuOption = NULL;
1470 IfrBinary = NULL;
1471 NvMap = NULL;
1472 NvMapSize = 0;
1473
1474 ZeroMem (&Key, sizeof (EFI_INPUT_KEY));
1475
1476 if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {
1477 TopRow = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;
1478 Row = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;
1479 } else {
1480 TopRow = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;
1481 Row = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;
1482 }
1483
1484 if (SubMenu) {
1485 Col = LocalScreen.LeftColumn;
1486 } else {
1487 Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS;
1488 }
1489
1490 BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1;
1491
1492 TopOfScreen = Menu.ForwardLink;
1493 Repaint = TRUE;
1494 MenuOption = NULL;
1495
1496 //
1497 // Get user's selection
1498 //
1499 Selection = NULL;
1500 NewPos = Menu.ForwardLink;
1501 gST->ConOut->EnableCursor (gST->ConOut, FALSE);
1502
1503 UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE);
1504
1505 ControlFlag = CfInitialization;
1506
1507 while (TRUE) {
1508 switch (ControlFlag) {
1509 case CfInitialization:
1510 ControlFlag = CfCheckSelection;
1511 if (gExitRequired) {
1512 ScreenOperation = UiReset;
1513 ControlFlag = CfScreenOperation;
1514 } else if (gSaveRequired) {
1515 ScreenOperation = UiSave;
1516 ControlFlag = CfScreenOperation;
1517 } else if (IsListEmpty (&Menu)) {
1518 ControlFlag = CfReadKey;
1519 }
1520 break;
1521
1522 case CfCheckSelection:
1523 if (Selection != NULL) {
1524 ControlFlag = CfExit;
1525 } else {
1526 ControlFlag = CfRepaint;
1527 }
1528
1529 FileFormTags = FileFormTagsHead;
1530 break;
1531
1532 case CfRepaint:
1533 ControlFlag = CfRefreshHighLight;
1534
1535 if (Repaint) {
1536 //
1537 // Display menu
1538 //
1539 SavedMenuOption = MenuOption;
1540 gDownArrow = FALSE;
1541 gUpArrow = FALSE;
1542 Row = TopRow;
1543
1544 Temp = SkipValue;
1545 Temp2 = SkipValue;
1546
1547 ClearLines (
1548 LocalScreen.LeftColumn,
1549 LocalScreen.RightColumn,
1550 TopRow - SCROLL_ARROW_HEIGHT,
1551 BottomRow + SCROLL_ARROW_HEIGHT,
1552 FIELD_TEXT | FIELD_BACKGROUND
1553 );
1554
1555 while (gMenuRefreshHead != NULL) {
1556 OldMenuRefreshEntry = gMenuRefreshHead->Next;
1557
1558 FreePool (gMenuRefreshHead);
1559
1560 gMenuRefreshHead = OldMenuRefreshEntry;
1561 }
1562
1563 for (Link = TopOfScreen; Link != &Menu; Link = Link->ForwardLink) {
1564 MenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
1565 MenuOption->Row = Row;
1566 OriginalRow = Row;
1567 MenuOption->Col = Col;
1568 MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;
1569
1570 if (SubMenu) {
1571 if (MenuOption->ThisTag->GrayOut) {
1572 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);
1573 } else {
1574 if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) {
1575 gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);
1576 }
1577 }
1578
1579 Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);
1580
1581 OriginalRow = Row;
1582
1583 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {
1584 if ((Temp == 0) && (Row <= BottomRow)) {
1585 PrintStringAt (Col, Row, OutputString);
1586 }
1587 //
1588 // If there is more string to process print on the next row and increment the Skip value
1589 //
1590 if (StrLen (&MenuOption->Description[Index])) {
1591 if (Temp == 0) {
1592 Row++;
1593 }
1594 }
1595
1596 FreePool (OutputString);
1597 if (Temp != 0) {
1598 Temp--;
1599 }
1600 }
1601
1602 Temp = 0;
1603
1604 Row = OriginalRow;
1605
1606 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
1607 ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);
1608
1609 if (OptionString != NULL) {
1610 if (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||
1611 MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP
1612 ) {
1613 //
1614 // If leading spaces on OptionString - remove the spaces
1615 //
1616 for (Index = 0; OptionString[Index] == L' '; Index++) {
1617 MenuOption->OptCol++;
1618 }
1619
1620 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {
1621 OptionString[Count] = OptionString[Index];
1622 Count++;
1623 }
1624
1625 OptionString[Count] = CHAR_NULL;
1626 }
1627
1628 //
1629 // If this is a date or time op-code and is used to reflect an RTC, register the op-code
1630 //
1631 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||
1632 MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP) &&
1633 (MenuOption->ThisTag->StorageStart >= FileFormTags->FormTags.Tags[0].NvDataSize)) {
1634
1635 if (gMenuRefreshHead == NULL) {
1636 MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));
1637 ASSERT (MenuRefreshEntry != NULL);
1638 MenuRefreshEntry->MenuOption = MenuOption;
1639 MenuRefreshEntry->FileFormTagsHead = FileFormTagsHead;
1640 MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;
1641 MenuRefreshEntry->CurrentRow = MenuOption->Row;
1642 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;
1643 gMenuRefreshHead = MenuRefreshEntry;
1644 } else {
1645 //
1646 // Advance to the last entry
1647 //
1648 for (MenuRefreshEntry = gMenuRefreshHead;
1649 MenuRefreshEntry->Next != NULL;
1650 MenuRefreshEntry = MenuRefreshEntry->Next
1651 )
1652 ;
1653 MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));
1654 ASSERT (MenuRefreshEntry->Next != NULL);
1655 MenuRefreshEntry = MenuRefreshEntry->Next;
1656 MenuRefreshEntry->MenuOption = MenuOption;
1657 MenuRefreshEntry->FileFormTagsHead = FileFormTagsHead;
1658 MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;
1659 MenuRefreshEntry->CurrentRow = MenuOption->Row;
1660 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;
1661 }
1662 }
1663
1664 Width = (UINT16) gOptionBlockWidth;
1665
1666 OriginalRow = Row;
1667
1668 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {
1669 if ((Temp2 == 0) && (Row <= BottomRow)) {
1670 PrintStringAt (MenuOption->OptCol, Row, OutputString);
1671 }
1672 //
1673 // If there is more string to process print on the next row and increment the Skip value
1674 //
1675 if (StrLen (&OptionString[Index])) {
1676 if (Temp2 == 0) {
1677 Row++;
1678 //
1679 // Since the Number of lines for this menu entry may or may not be reflected accurately
1680 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1681 // some testing to ensure we are keeping this in-sync.
1682 //
1683 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1684 //
1685 if ((Row - OriginalRow) >= MenuOption->Skip) {
1686 MenuOption->Skip++;
1687 }
1688 }
1689 }
1690
1691 FreePool (OutputString);
1692 if (Temp2 != 0) {
1693 Temp2--;
1694 }
1695 }
1696
1697 Temp2 = 0;
1698 Row = OriginalRow;
1699 }
1700 //
1701 // If this is a text op with secondary text information
1702 //
1703 if ((MenuOption->ThisTag->Operand == EFI_IFR_TEXT_OP) && (MenuOption->ThisTag->TextTwo != 0)) {
1704 StringPtr = GetToken (MenuOption->ThisTag->TextTwo, MenuOption->Handle);
1705
1706 Width = (UINT16) gOptionBlockWidth;
1707
1708 OriginalRow = Row;
1709
1710 for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) {
1711 if ((Temp == 0) && (Row <= BottomRow)) {
1712 PrintStringAt (MenuOption->OptCol, Row, OutputString);
1713 }
1714 //
1715 // If there is more string to process print on the next row and increment the Skip value
1716 //
1717 if (StrLen (&StringPtr[Index])) {
1718 if (Temp2 == 0) {
1719 Row++;
1720 //
1721 // Since the Number of lines for this menu entry may or may not be reflected accurately
1722 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1723 // some testing to ensure we are keeping this in-sync.
1724 //
1725 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1726 //
1727 if ((Row - OriginalRow) >= MenuOption->Skip) {
1728 MenuOption->Skip++;
1729 }
1730 }
1731 }
1732
1733 FreePool (OutputString);
1734 if (Temp2 != 0) {
1735 Temp2--;
1736 }
1737 }
1738
1739 Row = OriginalRow;
1740 FreePool (StringPtr);
1741 }
1742 } else {
1743 //
1744 // For now, assume left-justified 72 width max setup entries
1745 //
1746 PrintStringAt (Col, Row, MenuOption->Description);
1747 }
1748 //
1749 // Tracker 6210 - need to handle the bottom of the display
1750 //
1751 if (MenuOption->Skip > 1) {
1752 Row += MenuOption->Skip - SkipValue;
1753 SkipValue = 0;
1754 } else {
1755 Row += MenuOption->Skip;
1756 }
1757
1758 if (Row > BottomRow) {
1759 if (!ValueIsScroll (FALSE, Link)) {
1760 gDownArrow = TRUE;
1761 }
1762
1763 Row = BottomRow + 1;
1764 break;
1765 }
1766 }
1767
1768 if (!ValueIsScroll (TRUE, TopOfScreen)) {
1769 gUpArrow = TRUE;
1770 }
1771
1772 if (gUpArrow) {
1773 gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);
1774 PrintAt (
1775 LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,
1776 TopRow - SCROLL_ARROW_HEIGHT,
1777 (CHAR16 *) L"%c",
1778 ARROW_UP
1779 );
1780 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
1781 }
1782
1783 if (gDownArrow) {
1784 gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);
1785 PrintAt (
1786 LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,
1787 BottomRow + SCROLL_ARROW_HEIGHT,
1788 (CHAR16 *) L"%c",
1789 ARROW_DOWN
1790 );
1791 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
1792 }
1793
1794 if (SavedMenuOption != NULL) {
1795 MenuOption = SavedMenuOption;
1796 }
1797 }
1798 break;
1799
1800 case CfRefreshHighLight:
1801 ControlFlag = CfUpdateHelpString;
1802 //
1803 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily
1804 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.
1805 //
1806 SavedValue = Repaint;
1807 Repaint = FALSE;
1808
1809 if (NewPos != NULL) {
1810 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);
1811 if (SubMenu) {
1812 if (gLastOpr && (gEntryNumber != -1)) {
1813 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
1814 if (gEntryNumber != MenuOption->EntryNumber) {
1815 ScreenOperation = UiDown;
1816 ControlFlag = CfScreenOperation;
1817 break;
1818 } else {
1819 gLastOpr = FALSE;
1820 }
1821 }
1822
1823 ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);
1824 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
1825 if (OptionString != NULL) {
1826 if (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||
1827 MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP
1828 ) {
1829 //
1830 // If leading spaces on OptionString - remove the spaces
1831 //
1832 for (Index = 0; OptionString[Index] == L' '; Index++)
1833 ;
1834
1835 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {
1836 OptionString[Count] = OptionString[Index];
1837 Count++;
1838 }
1839
1840 OptionString[Count] = CHAR_NULL;
1841 }
1842
1843 Width = (UINT16) gOptionBlockWidth;
1844
1845 OriginalRow = MenuOption->Row;
1846
1847 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {
1848 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {
1849 PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);
1850 }
1851 //
1852 // If there is more string to process print on the next row and increment the Skip value
1853 //
1854 if (StrLen (&OptionString[Index])) {
1855 MenuOption->Row++;
1856 }
1857
1858 FreePool (OutputString);
1859 }
1860
1861 MenuOption->Row = OriginalRow;
1862 } else {
1863 if (NewLine) {
1864 if (MenuOption->ThisTag->GrayOut) {
1865 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);
1866 } else {
1867 if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) {
1868 gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);
1869 }
1870 }
1871
1872 OriginalRow = MenuOption->Row;
1873 Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);
1874
1875 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {
1876 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {
1877 PrintStringAt (Col, MenuOption->Row, OutputString);
1878 }
1879 //
1880 // If there is more string to process print on the next row and increment the Skip value
1881 //
1882 if (StrLen (&MenuOption->Description[Index])) {
1883 MenuOption->Row++;
1884 }
1885
1886 FreePool (OutputString);
1887 }
1888
1889 MenuOption->Row = OriginalRow;
1890 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
1891 }
1892 }
1893 } else {
1894 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
1895 gST->ConOut->OutputString (gST->ConOut, MenuOption->Description);
1896 }
1897
1898 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
1899
1900 if ((gPriorMenuEntry != 0) && (MenuOption->EntryNumber != gPriorMenuEntry) && (NewPos->ForwardLink != &Menu)) {
1901 ScreenOperation = UiDown;
1902 ControlFlag = CfScreenOperation;
1903 break;
1904 } else {
1905 gPriorMenuEntry = 0;
1906 }
1907 //
1908 // This is only possible if we entered this page and the first menu option is
1909 // a "non-menu" item. In that case, force it UiDown
1910 //
1911 if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) {
1912 //
1913 // If we previously hit an UP command and we are still sitting on a text operation
1914 // we must continue going up
1915 //
1916 if (ScreenOperation == UiUp) {
1917 ControlFlag = CfScreenOperation;
1918 break;
1919 } else {
1920 ScreenOperation = UiDown;
1921 ControlFlag = CfScreenOperation;
1922 break;
1923 }
1924 }
1925 //
1926 // Set reverse attribute
1927 //
1928 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);
1929 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);
1930
1931 //
1932 // Assuming that we have a refresh linked-list created, lets annotate the
1933 // appropriate entry that we are highlighting with its new attribute. Just prior to this
1934 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh
1935 //
1936 if (gMenuRefreshHead != NULL) {
1937 for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) {
1938 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;
1939 if (MenuRefreshEntry->MenuOption == MenuOption) {
1940 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT;
1941 }
1942 }
1943 }
1944
1945 if (SubMenu) {
1946 ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);
1947 if (OptionString != NULL) {
1948 if (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||
1949 MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP
1950 ) {
1951 //
1952 // If leading spaces on OptionString - remove the spaces
1953 //
1954 for (Index = 0; OptionString[Index] == L' '; Index++)
1955 ;
1956
1957 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {
1958 OptionString[Count] = OptionString[Index];
1959 Count++;
1960 }
1961
1962 OptionString[Count] = CHAR_NULL;
1963 }
1964 Width = (UINT16) gOptionBlockWidth;
1965
1966 OriginalRow = MenuOption->Row;
1967
1968 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {
1969 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {
1970 PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);
1971 }
1972 //
1973 // If there is more string to process print on the next row and increment the Skip value
1974 //
1975 if (StrLen (&OptionString[Index])) {
1976 MenuOption->Row++;
1977 }
1978
1979 FreePool (OutputString);
1980 }
1981
1982 MenuOption->Row = OriginalRow;
1983 } else {
1984 if (NewLine) {
1985 OriginalRow = MenuOption->Row;
1986
1987 Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);
1988
1989 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {
1990 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {
1991 PrintStringAt (Col, MenuOption->Row, OutputString);
1992 }
1993 //
1994 // If there is more string to process print on the next row and increment the Skip value
1995 //
1996 if (StrLen (&MenuOption->Description[Index])) {
1997 MenuOption->Row++;
1998 }
1999
2000 FreePool (OutputString);
2001 }
2002
2003 MenuOption->Row = OriginalRow;
2004
2005 }
2006 }
2007
2008 if (((NewPos->ForwardLink != &Menu) && (ScreenOperation == UiDown)) ||
2009 ((NewPos->BackLink != &Menu) && (ScreenOperation == UiUp)) ||
2010 (ScreenOperation == UiNoOperation)
2011 ) {
2012 UpdateKeyHelp (MenuOption, FALSE);
2013 }
2014 } else {
2015 gST->ConOut->OutputString (gST->ConOut, MenuOption->Description);
2016 }
2017 //
2018 // Clear reverse attribute
2019 //
2020 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
2021 }
2022 //
2023 // Repaint flag will be used when process CfUpdateHelpString, so restore its value
2024 // if we didn't break halfway when process CfRefreshHighLight.
2025 //
2026 Repaint = SavedValue;
2027 break;
2028
2029 case CfUpdateHelpString:
2030 ControlFlag = CfPrepareToReadKey;
2031
2032 if (SubMenu &&
2033 (Repaint || NewLine ||
2034 (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||
2035 (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) &&
2036 !(gClassOfVfr == EFI_GENERAL_APPLICATION_SUBCLASS)) {
2037 //
2038 // Don't print anything if it is a NULL help token
2039 //
2040 if (MenuOption->ThisTag->Help == 0x00000000) {
2041 StringPtr = (CHAR16 *) L"\0";
2042 } else {
2043 StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle);
2044 }
2045
2046 ProcessHelpString (StringPtr, &FormattedString, BottomRow - TopRow);
2047
2048 gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND);
2049
2050 for (Index = 0; Index < BottomRow - TopRow; Index++) {
2051 //
2052 // Pad String with spaces to simulate a clearing of the previous line
2053 //
2054 for (; GetStringWidth (&FormattedString[Index * gHelpBlockWidth * 2]) / 2 < gHelpBlockWidth;) {
2055 StrCat (&FormattedString[Index * gHelpBlockWidth * 2], (CHAR16 *) L" ");
2056 }
2057
2058 PrintStringAt (
2059 LocalScreen.RightColumn - gHelpBlockWidth,
2060 Index + TopRow,
2061 &FormattedString[Index * gHelpBlockWidth * 2]
2062 );
2063 }
2064 }
2065 //
2066 // Reset this flag every time we finish using it.
2067 //
2068 Repaint = FALSE;
2069 NewLine = FALSE;
2070 break;
2071
2072 case CfPrepareToReadKey:
2073 ControlFlag = CfReadKey;
2074
2075 for (Index = 0; Index < MenuOption->IfrNumber; Index++) {
2076 FileFormTags = FileFormTags->NextFile;
2077 }
2078
2079 ScreenOperation = UiNoOperation;
2080
2081 Status = gBS->HandleProtocol (
2082 (VOID *) (UINTN) FileFormTags->FormTags.Tags[0].CallbackHandle,
2083 &gEfiFormCallbackProtocolGuid,
2084 (VOID **) &FormCallback
2085 );
2086
2087 break;
2088
2089 case CfReadKey:
2090 ControlFlag = CfScreenOperation;
2091
2092 OriginalTimeOut = FrontPageTimeOutValue;
2093 do {
2094 if (FrontPageTimeOutValue >= 0 && (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) && FrontPageTimeOutValue != (INT16) -1) {
2095 //
2096 // Remember that if set to 0, must immediately boot an option
2097 //
2098 if (FrontPageTimeOutValue == 0) {
2099 FrontPageTimeOutValue = 0xFFFF;
2100 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
2101 if (EFI_ERROR (Status)) {
2102 Status = EFI_TIMEOUT;
2103 }
2104 break;
2105 }
2106
2107 Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, ONE_SECOND);
2108 if (Status == EFI_TIMEOUT) {
2109 EFI_IFR_DATA_ENTRY *DataEntry;
2110
2111 DataEntry = (EFI_IFR_DATA_ENTRY *) (PageData + 1);
2112
2113 PageData->EntryCount = 1;
2114 Count = (UINT32) ((OriginalTimeOut - FrontPageTimeOutValue) * 100 / OriginalTimeOut);
2115 CopyMem (&DataEntry->Data, &Count, sizeof (UINT32));
2116
2117 if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {
2118 FormCallback->Callback (
2119 FormCallback,
2120 0xFFFF,
2121 (EFI_IFR_DATA_ARRAY *) PageData,
2122 NULL
2123 );
2124 }
2125 //
2126 // Count down 1 second
2127 //
2128 FrontPageTimeOutValue--;
2129
2130 } else {
2131 ASSERT (!EFI_ERROR (Status));
2132 PageData->EntryCount = 0;
2133 if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {
2134 FormCallback->Callback (
2135 FormCallback,
2136 0xFFFE,
2137 (EFI_IFR_DATA_ARRAY *) PageData,
2138 NULL
2139 );
2140 }
2141
2142 FrontPageTimeOutValue = 0xFFFF;
2143 }
2144 } else {
2145 //
2146 // Wait for user's selection, no auto boot
2147 //
2148 Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0);
2149 }
2150 } while (Status == EFI_TIMEOUT);
2151
2152 if (gFirstIn) {
2153 gFirstIn = FALSE;
2154 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
2155 DisableQuietBoot ();
2156 }
2157
2158 if (Status == EFI_TIMEOUT) {
2159 Key.UnicodeChar = CHAR_CARRIAGE_RETURN;
2160 } else {
2161 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
2162 //
2163 // if we encounter error, continue to read another key in.
2164 //
2165 if (EFI_ERROR (Status)) {
2166 ControlFlag = CfReadKey;
2167 continue;
2168 }
2169 }
2170
2171 switch (Key.UnicodeChar) {
2172 case CHAR_CARRIAGE_RETURN:
2173 Selection = MenuOption;
2174 ScreenOperation = UiSelect;
2175 gDirection = 0;
2176 break;
2177
2178 //
2179 // We will push the adjustment of these numeric values directly to the input handler
2180 //
2181 case '+':
2182 case '-':
2183 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {
2184
2185 if (Key.UnicodeChar == '+') {
2186 gDirection = SCAN_RIGHT;
2187 } else {
2188 gDirection = SCAN_LEFT;
2189 }
2190
2191 Status = ProcessOptions (MenuOption, TRUE, FileFormTagsHead, NULL, &OptionString);
2192 }
2193 break;
2194
2195 case '^':
2196 ScreenOperation = UiUp;
2197 break;
2198
2199 case 'V':
2200 case 'v':
2201 ScreenOperation = UiDown;
2202 break;
2203
2204 case ' ':
2205 if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {
2206 if (SubMenu) {
2207 if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !(MenuOption->ThisTag->GrayOut)) {
2208 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);
2209 gST->ConOut->OutputString (gST->ConOut, MenuOption->Description);
2210 Selection = MenuOption;
2211 ScreenOperation = UiSelect;
2212 }
2213 }
2214 }
2215 break;
2216
2217 case CHAR_NULL:
2218 if (((Key.ScanCode == SCAN_F1) && ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE)) ||
2219 ((Key.ScanCode == SCAN_F2) && ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO)) ||
2220 ((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) ||
2221 ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN))
2222 ) {
2223 //
2224 // If the function key has been disabled, just ignore the key.
2225 //
2226 } else {
2227 for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) {
2228 if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {
2229 if ((Key.ScanCode == SCAN_F9) || (Key.ScanCode == SCAN_F10)) {
2230 if (SubMenu) {
2231 ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;
2232 }
2233 } else {
2234 ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;
2235 }
2236 }
2237 }
2238 }
2239 break;
2240 }
2241 break;
2242
2243 case CfScreenOperation:
2244 IfrBinary = gBinaryDataHead;
2245
2246 //
2247 // Advance to the Ifr we are using
2248 //
2249 for (Index = 0; Index < gActiveIfr; Index++) {
2250 IfrBinary = IfrBinary->Next;
2251 }
2252
2253 if (ScreenOperation != UiPrevious && ScreenOperation != UiReset) {
2254 //
2255 // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset
2256 // ignore the selection and go back to reading keys.
2257 //
2258 if (IsListEmpty (&Menu)) {
2259 ControlFlag = CfReadKey;
2260 break;
2261 }
2262 //
2263 // if there is nothing logical to place a cursor on, just move on to wait for a key.
2264 //
2265 for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) {
2266 NextMenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
2267 if (!(NextMenuOption->ThisTag->GrayOut) && (NextMenuOption->ThisTag->Operand != EFI_IFR_SUBTITLE_OP)) {
2268 break;
2269 }
2270 }
2271
2272 if (Link == &Menu) {
2273 ControlFlag = CfPrepareToReadKey;
2274 break;
2275 }
2276 }
2277
2278 for (Index = 0;
2279 Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);
2280 Index++
2281 ) {
2282 if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {
2283 ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;
2284 }
2285 }
2286
2287 break;
2288
2289 case CfUiPrevious:
2290 ControlFlag = CfCheckSelection;
2291 //
2292 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2293 //
2294 if (MenuOption != NULL) {
2295 if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {
2296 Selection = NULL;
2297 Repaint = TRUE;
2298 break;
2299 }
2300 }
2301
2302 if (IsListEmpty (&gMenuList)) {
2303 Selection = NULL;
2304 if (IsListEmpty (&Menu)) {
2305 ControlFlag = CfReadKey;
2306 }
2307 break;
2308 }
2309
2310 gLastOpr = TRUE;
2311
2312 while (gMenuRefreshHead != NULL) {
2313 OldMenuRefreshEntry = gMenuRefreshHead->Next;
2314
2315 FreePool (gMenuRefreshHead);
2316
2317 gMenuRefreshHead = OldMenuRefreshEntry;
2318 }
2319 //
2320 // Remove the Cached page entry, free and init the menus, flag Selection as jumping to previous page and a valid Tag
2321 //
2322 if (SubMenu) {
2323 UiRemoveMenuListEntry (MenuOption, &Selection);
2324 Selection->Previous = TRUE;
2325 UiFreeMenu ();
2326 UiInitMenu ();
2327 }
2328
2329 gActiveIfr = Selection->IfrNumber;
2330 return Selection;
2331
2332 case CfUiSelect:
2333 ControlFlag = CfCheckSelection;
2334
2335 ExtractRequestedNvMap (FileFormTags, MenuOption->ThisTag->VariableNumber, &VariableDefinition);
2336
2337 if (SubMenu) {
2338 if ((MenuOption->ThisTag->Operand == EFI_IFR_TEXT_OP &&
2339 !(MenuOption->ThisTag->Flags & EFI_IFR_FLAG_INTERACTIVE)) ||
2340 (MenuOption->ThisTag->GrayOut) ||
2341 (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||
2342 (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {
2343 Selection = NULL;
2344 break;
2345 }
2346
2347 NewLine = TRUE;
2348 UpdateKeyHelp (MenuOption, TRUE);
2349 Status = ProcessOptions (MenuOption, TRUE, FileFormTagsHead, PageData, &OptionString);
2350
2351 if (EFI_ERROR (Status)) {
2352 Selection = NULL;
2353 Repaint = TRUE;
2354 break;
2355 }
2356
2357 if (OptionString != NULL) {
2358 PrintStringAt (LocalScreen.LeftColumn + gPromptBlockWidth + 1, MenuOption->Row, OptionString);
2359 }
2360
2361 if (MenuOption->ThisTag->Flags & EFI_IFR_FLAG_INTERACTIVE) {
2362 Selection = MenuOption;
2363 }
2364
2365 if (Selection == NULL) {
2366 break;
2367 }
2368
2369 Location = (UINT8 *) &PageData->EntryCount;
2370
2371 //
2372 // If not a goto, dump single piece of data, otherwise dump everything
2373 //
2374 if (Selection->ThisTag->Operand == EFI_IFR_REF_OP) {
2375 //
2376 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2377 //
2378 if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {
2379 Selection = NULL;
2380 Repaint = TRUE;
2381 break;
2382 }
2383
2384 UiAddMenuListEntry (Selection);
2385 gPriorMenuEntry = 0;
2386
2387 //
2388 // Now that we added a menu entry specific to a goto, we can always go back when someone hits the UiPrevious
2389 //
2390 UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);
2391 UiMenuList->FormerEntryNumber = MenuOption->EntryNumber;
2392
2393 gLastOpr = FALSE;
2394
2395 //
2396 // Rewind to the beginning of the menu
2397 //
2398 for (; NewPos->BackLink != &Menu; NewPos = NewPos->BackLink)
2399 ;
2400
2401 //
2402 // Get Total Count of Menu entries
2403 //
2404 for (Count = 1; NewPos->ForwardLink != &Menu; NewPos = NewPos->ForwardLink) {
2405 Count++;
2406 }
2407 //
2408 // Rewind to the beginning of the menu
2409 //
2410 for (; NewPos->BackLink != &Menu; NewPos = NewPos->BackLink)
2411 ;
2412
2413 //
2414 // Copy the number of entries being described to the PageData location
2415 //
2416 CopyMem (&Location[0], &Count, sizeof (UINT32));
2417
2418 for (Index = 4; NewPos->ForwardLink != &Menu; Index = Index + MenuOption->ThisTag->StorageWidth + 2) {
2419
2420 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
2421 Location[Index] = MenuOption->ThisTag->Operand;
2422 Location[Index + 1] = (UINT8) (MenuOption->ThisTag->StorageWidth + 4);
2423 CopyMem (
2424 &Location[Index + 4],
2425 &VariableDefinition->NvRamMap[MenuOption->ThisTag->StorageStart],
2426 MenuOption->ThisTag->StorageWidth
2427 );
2428 NewPos = NewPos->ForwardLink;
2429 }
2430 } else {
2431
2432 gPriorMenuEntry = MenuOption->EntryNumber;
2433
2434 Count = 1;
2435
2436 //
2437 // Copy the number of entries being described to the PageData location
2438 //
2439 CopyMem (&Location[0], &Count, sizeof (UINT32));
2440
2441 //
2442 // Start at PageData[4] since the EntryCount is a UINT32
2443 //
2444 Index = 4;
2445
2446 //
2447 // Copy data to destination
2448 //
2449 Location[Index] = MenuOption->ThisTag->Operand;
2450 Location[Index + 1] = (UINT8) (MenuOption->ThisTag->StorageWidth + 4);
2451 CopyMem (
2452 &Location[Index + 4],
2453 &VariableDefinition->NvRamMap[MenuOption->ThisTag->StorageStart],
2454 MenuOption->ThisTag->StorageWidth
2455 );
2456 }
2457 }
2458 break;
2459
2460 case CfUiReset:
2461 ControlFlag = CfCheckSelection;
2462 gLastOpr = FALSE;
2463 if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {
2464 break;
2465 }
2466 //
2467 // If NV flag is up, prompt user
2468 //
2469 if (gNvUpdateRequired) {
2470 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
2471
2472 YesResponse = gYesResponse[0];
2473 NoResponse = gNoResponse[0];
2474
2475 do {
2476 CreateDialog (3, TRUE, 0, NULL, &Key, gEmptyString, gAreYouSure, gEmptyString);
2477 } while
2478 (
2479 (Key.ScanCode != SCAN_ESC) &&
2480 ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&
2481 ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))
2482 );
2483
2484 //
2485 // If the user hits the YesResponse key
2486 //
2487 if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {
2488 } else {
2489 Repaint = TRUE;
2490 NewLine = TRUE;
2491 break;
2492 }
2493 }
2494 //
2495 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2496 //
2497 if (MenuOption != NULL) {
2498 if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {
2499 Selection = NULL;
2500 Repaint = TRUE;
2501 NewLine = TRUE;
2502 break;
2503 }
2504 }
2505
2506 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
2507 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
2508
2509 if (SubMenu) {
2510 UiFreeMenuList ();
2511 gST->ConOut->ClearScreen (gST->ConOut);
2512 return NULL;
2513 }
2514
2515 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);
2516 UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, FALSE);
2517
2518 if (IfrBinary->UnRegisterOnExit) {
2519 Hii->RemovePack (Hii, MenuOption->Handle);
2520 }
2521
2522 UiFreeMenu ();
2523
2524 //
2525 // Clean up the allocated data buffers
2526 //
2527 FreeData (FileFormTagsHead, FormattedString, OptionString);
2528
2529 gST->ConOut->ClearScreen (gST->ConOut);
2530 return NULL;
2531
2532 case CfUiLeft:
2533 ControlFlag = CfCheckSelection;
2534 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {
2535 if (MenuOption->Skip == 1) {
2536 //
2537 // In the tail of the Date/Time op-code set, go left.
2538 //
2539 NewPos = NewPos->BackLink;
2540 } else {
2541 //
2542 // In the middle of the Data/Time op-code set, go left.
2543 //
2544 NextMenuOption = CR (NewPos->ForwardLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
2545 if (NextMenuOption->Skip == 1) {
2546 NewPos = NewPos->BackLink;
2547 }
2548 }
2549 }
2550 break;
2551
2552 case CfUiRight:
2553 ControlFlag = CfCheckSelection;
2554 if ((MenuOption->Skip == 0) &&
2555 ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP))
2556 ) {
2557 //
2558 // We are in the head or middle of the Date/Time op-code set, advance right.
2559 //
2560 NewPos = NewPos->ForwardLink;
2561 }
2562 break;
2563
2564 case CfUiUp:
2565 ControlFlag = CfCheckSelection;
2566
2567 if (NewPos->BackLink != &Menu) {
2568 NewLine = TRUE;
2569 //
2570 // Adjust Date/Time position before we advance forward.
2571 //
2572 AdjustDateAndTimePosition (TRUE, &NewPos);
2573
2574 //
2575 // Caution that we have already rewind to the top, don't go backward in this situation.
2576 //
2577 if (NewPos->BackLink != &Menu) {
2578 NewPos = NewPos->BackLink;
2579 }
2580
2581 PreviousMenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
2582
2583 //
2584 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended
2585 // to be one that back to the previous set of op-codes, we need to advance to the sencond
2586 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
2587 // checking can be done.
2588 //
2589 DataAndTimeLineNumberPad = AdjustDateAndTimePosition (TRUE, &NewPos);
2590
2591 if (SubMenu) {
2592 //
2593 // If the previous MenuOption contains a display-only op-code, skip to the next one
2594 //
2595 if (PreviousMenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || PreviousMenuOption->ThisTag->GrayOut) {
2596 //
2597 // This is ok as long as not at the end of the list
2598 //
2599 if (NewPos->BackLink == &Menu) {
2600 //
2601 // If we are at the start of the list, then this list must start with a display only
2602 // piece of data, so do not allow the backward motion
2603 //
2604 ScreenOperation = UiDown;
2605
2606 if (PreviousMenuOption->Row <= TopRow) {
2607 if (TopOfScreen->BackLink != &Menu) {
2608 TopOfScreen = TopOfScreen->BackLink;
2609 Repaint = TRUE;
2610 }
2611 }
2612
2613 UpdateStatusBar (INPUT_ERROR, PreviousMenuOption->ThisTag->Flags, FALSE);
2614 break;
2615 }
2616 }
2617 }
2618 //
2619 // Check the previous menu entry to see if it was a zero-length advance. If it was,
2620 // don't worry about a redraw.
2621 //
2622 if ((MenuOption->Row - PreviousMenuOption->Skip - DataAndTimeLineNumberPad < TopRow) ||
2623 (PreviousMenuOption->Skip > MenuOption->Row)
2624 ) {
2625 do {
2626 if (TopOfScreen->BackLink == &Menu) {
2627 break;
2628 }
2629
2630 Repaint = TRUE;
2631
2632 //
2633 // Is the current top of screen a zero-advance op-code?
2634 // If so, keep moving forward till we hit a >0 advance op-code
2635 //
2636 SavedMenuOption = CR (TopOfScreen->BackLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
2637 TopOfScreen = TopOfScreen->BackLink;
2638 } while (SavedMenuOption->Skip == 0);
2639 //
2640 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2641 //
2642 AdjustDateAndTimePosition (TRUE, &TopOfScreen);
2643 }
2644
2645 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);
2646 } else {
2647 if (SubMenu) {
2648 SavedMenuOption = MenuOption;
2649 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
2650 if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) {
2651 //
2652 // If we are at the end of the list and sitting on a text op, we need to more forward
2653 //
2654 ScreenOperation = UiDown;
2655 ControlFlag = CfScreenOperation;
2656 break;
2657 }
2658
2659 MenuOption = SavedMenuOption;
2660 }
2661 }
2662 break;
2663
2664 case CfUiPageUp:
2665 ControlFlag = CfCheckSelection;
2666
2667 SavedListEntry = NewPos;
2668 Link = TopOfScreen;
2669 for (Index = BottomRow; Index >= TopRow + 1; Index -= MenuOption->Skip) {
2670 if (Link->BackLink == &Menu) {
2671 TopOfScreen = Link;
2672 Link = SavedListEntry;
2673 MenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
2674 break;
2675 }
2676
2677 NewLine = TRUE;
2678 Repaint = TRUE;
2679 Link = Link->BackLink;
2680 MenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
2681 TopOfScreen = Link;
2682 SavedListEntry = Link;
2683 }
2684
2685 NewPos = Link;
2686
2687 //
2688 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2689 // Don't do this when we are already in the first page.
2690 //
2691 if (Repaint) {
2692 AdjustDateAndTimePosition (TRUE, &TopOfScreen);
2693 AdjustDateAndTimePosition (TRUE, &NewPos);
2694 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
2695 }
2696 break;
2697
2698 case CfUiPageDown:
2699 ControlFlag = CfCheckSelection;
2700
2701 SavedListEntry = NewPos;
2702 Link = TopOfScreen;
2703 NewPos = TopOfScreen;
2704 for (Index = TopRow; Index <= BottomRow - 1; Index += MenuOption->Skip) {
2705 if (NewPos->ForwardLink == &Menu) {
2706 NewPos = SavedListEntry;
2707 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
2708 Link = TopOfScreen;
2709 NewLine = FALSE;
2710 Repaint = FALSE;
2711 break;
2712 }
2713
2714 NewLine = TRUE;
2715 Repaint = TRUE;
2716 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
2717 NewPos = NewPos->ForwardLink;
2718 Link = NewPos;
2719 }
2720
2721 TopOfScreen = Link;
2722
2723 //
2724 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2725 // Don't do this when we are already in the last page.
2726 //
2727 if (Repaint) {
2728 AdjustDateAndTimePosition (TRUE, &TopOfScreen);
2729 AdjustDateAndTimePosition (TRUE, &NewPos);
2730 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
2731 }
2732 break;
2733
2734 case CfUiDown:
2735 ControlFlag = CfCheckSelection;
2736 //
2737 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
2738 // to be one that progresses to the next set of op-codes, we need to advance to the last
2739 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
2740 // checking can be done. The only other logic we need to introduce is that if a Date/Time
2741 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
2742 // the Date/Time op-code.
2743 //
2744 DataAndTimeLineNumberPad = AdjustDateAndTimePosition (FALSE, &NewPos);
2745
2746 if (NewPos->ForwardLink != &Menu) {
2747 NewLine = TRUE;
2748 NewPos = NewPos->ForwardLink;
2749 NextMenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
2750
2751 if (SubMenu) {
2752 //
2753 // If the next MenuOption contains a display-only op-code, skip to the next one
2754 // Also if the next MenuOption is date or time,
2755 //
2756 if (NextMenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || NextMenuOption->ThisTag->GrayOut) {
2757 //
2758 // This is ok as long as not at the end of the list
2759 //
2760 if (NewPos == &Menu) {
2761 //
2762 // If we are at the end of the list, then this list must end with a display only
2763 // piece of data, so do not allow the forward motion
2764 //
2765 UpdateStatusBar (INPUT_ERROR, NextMenuOption->ThisTag->Flags, FALSE);
2766 NewPos = NewPos->BackLink;
2767 ScreenOperation = UiUp;
2768 break;
2769 }
2770 }
2771 }
2772 //
2773 // An option might be multi-line, so we need to reflect that data in the overall skip value
2774 //
2775 UpdateOptionSkipLines (PageData, NextMenuOption, FileFormTagsHead, &OptionString, SkipValue);
2776
2777 if (NextMenuOption->Skip > 1) {
2778 Temp = MenuOption->Row + MenuOption->Skip + NextMenuOption->Skip - 1;
2779 } else {
2780 Temp = MenuOption->Row + MenuOption->Skip + DataAndTimeLineNumberPad;
2781 }
2782 //
2783 // If we are going to scroll
2784 //
2785 if (Temp > BottomRow) {
2786 do {
2787 //
2788 // Is the current top of screen a zero-advance op-code?
2789 // If so, keep moving forward till we hit a >0 advance op-code
2790 //
2791 SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
2792
2793 //
2794 // If bottom op-code is more than one line or top op-code is more than one line
2795 //
2796 if ((NextMenuOption->Skip > 1) || (MenuOption->Skip > 1)) {
2797 //
2798 // Is the bottom op-code greater than or equal in size to the top op-code?
2799 //
2800 if ((Temp - BottomRow) >= (SavedMenuOption->Skip - OldSkipValue)) {
2801 //
2802 // Skip the top op-code
2803 //
2804 TopOfScreen = TopOfScreen->ForwardLink;
2805 Difference = (Temp - BottomRow) - (SavedMenuOption->Skip - OldSkipValue);
2806
2807 OldSkipValue = Difference;
2808
2809 SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
2810
2811 //
2812 // If we have a remainder, skip that many more op-codes until we drain the remainder
2813 //
2814 for (;
2815 Difference >= (INTN) SavedMenuOption->Skip;
2816 Difference = Difference - (INTN) SavedMenuOption->Skip
2817 ) {
2818 //
2819 // Since the Difference is greater than or equal to this op-code's skip value, skip it
2820 //
2821 TopOfScreen = TopOfScreen->ForwardLink;
2822 SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
2823 if (Difference < (INTN) SavedMenuOption->Skip) {
2824 Difference = SavedMenuOption->Skip - Difference - 1;
2825 break;
2826 } else {
2827 if (Difference == (INTN) SavedMenuOption->Skip) {
2828 TopOfScreen = TopOfScreen->ForwardLink;
2829 SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
2830 Difference = SavedMenuOption->Skip - Difference;
2831 break;
2832 }
2833 }
2834 }
2835 //
2836 // Since we will act on this op-code in the next routine, and increment the
2837 // SkipValue, set the skips to one less than what is required.
2838 //
2839 SkipValue = Difference - 1;
2840
2841 } else {
2842 //
2843 // Since we will act on this op-code in the next routine, and increment the
2844 // SkipValue, set the skips to one less than what is required.
2845 //
2846 SkipValue = OldSkipValue + (Temp - BottomRow) - 1;
2847 }
2848 } else {
2849 if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) {
2850 TopOfScreen = TopOfScreen->ForwardLink;
2851 break;
2852 } else {
2853 SkipValue = OldSkipValue;
2854 }
2855 }
2856 //
2857 // If the op-code at the top of the screen is more than one line, let's not skip it yet
2858 // Let's set a skip flag to smoothly scroll the top of the screen.
2859 //
2860 if (SavedMenuOption->Skip > 1) {
2861 if (SavedMenuOption == NextMenuOption) {
2862 SkipValue = 0;
2863 } else {
2864 SkipValue++;
2865 }
2866 } else {
2867 SkipValue = 0;
2868 TopOfScreen = TopOfScreen->ForwardLink;
2869 }
2870 } while (SavedMenuOption->Skip == 0);
2871
2872 Repaint = TRUE;
2873 OldSkipValue = SkipValue;
2874 }
2875
2876 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);
2877
2878 } else {
2879 if (SubMenu) {
2880 SavedMenuOption = MenuOption;
2881 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
2882 if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) {
2883 //
2884 // If we are at the end of the list and sitting on a text op, we need to more forward
2885 //
2886 ScreenOperation = UiUp;
2887 ControlFlag = CfScreenOperation;
2888 break;
2889 }
2890
2891 MenuOption = SavedMenuOption;
2892 //
2893 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
2894 //
2895 AdjustDateAndTimePosition (TRUE, &NewPos);
2896 }
2897 }
2898 break;
2899
2900 case CfUiSave:
2901 ControlFlag = CfCheckSelection;
2902 //
2903 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2904 //
2905 if (MenuOption != NULL) {
2906 if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {
2907 Selection = NULL;
2908 Repaint = TRUE;
2909 break;
2910 }
2911 }
2912 //
2913 // If callbacks are active, and the callback has a Write method, try to use it
2914 //
2915 if (FileFormTags->VariableDefinitions->VariableName == NULL) {
2916 if ((FormCallback != NULL) && (FormCallback->NvWrite != NULL)) {
2917 Status = FormCallback->NvWrite (
2918 FormCallback,
2919 (CHAR16 *) L"Setup",
2920 &FileFormTags->FormTags.Tags[0].GuidValue,
2921 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
2922 VariableDefinition->VariableSize,
2923 (VOID *) VariableDefinition->NvRamMap,
2924 &gResetRequired
2925 );
2926
2927 } else {
2928 Status = gRT->SetVariable (
2929 (CHAR16 *) L"Setup",
2930 &FileFormTags->FormTags.Tags[0].GuidValue,
2931 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
2932 VariableDefinition->VariableSize,
2933 (VOID *) VariableDefinition->NvRamMap
2934 );
2935 }
2936 } else {
2937 VariableDefinition = FileFormTags->VariableDefinitions;
2938
2939 for (; VariableDefinition != NULL; VariableDefinition = VariableDefinition->Next) {
2940 if ((FormCallback != NULL) && (FormCallback->NvWrite != NULL)) {
2941 Status = FormCallback->NvWrite (
2942 FormCallback,
2943 VariableDefinition->VariableName,
2944 &VariableDefinition->Guid,
2945 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
2946 VariableDefinition->VariableSize,
2947 (VOID *) VariableDefinition->NvRamMap,
2948 &gResetRequired
2949 );
2950
2951 } else {
2952 Status = gRT->SetVariable (
2953 VariableDefinition->VariableName,
2954 &VariableDefinition->Guid,
2955 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
2956 VariableDefinition->VariableSize,
2957 (VOID *) VariableDefinition->NvRamMap
2958 );
2959 }
2960 }
2961 }
2962
2963 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);
2964 UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, FALSE);
2965 break;
2966
2967 case CfUiDefault:
2968 ControlFlag = CfCheckSelection;
2969
2970 NvMapListHead = NULL;
2971
2972 Status = Hii->GetDefaultImage (Hii, MenuOption->Handle, EFI_IFR_FLAG_DEFAULT, &NvMapListHead);
2973
2974 if (!EFI_ERROR (Status)) {
2975 ASSERT_EFI_ERROR (NULL != NvMapListHead);
2976
2977 NvMapListNode = NvMapListHead;
2978
2979 while (NULL != NvMapListNode) {
2980 if (FileFormTags->VariableDefinitions->VariableId == NvMapListNode->VariablePack->VariableId) {
2981 NvMap = (VOID *) ((CHAR8 *) NvMapListNode->VariablePack + sizeof (EFI_HII_VARIABLE_PACK) + NvMapListNode->VariablePack->VariableNameLength);
2982 NvMapSize = NvMapListNode->VariablePack->Header.Length - sizeof (EFI_HII_VARIABLE_PACK) - NvMapListNode->VariablePack->VariableNameLength;
2983 break;
2984 }
2985 NvMapListNode = NvMapListNode->NextVariablePack;
2986 }
2987
2988 //
2989 // Free the buffer that was allocated.
2990 //
2991 FreePool (FileFormTags->VariableDefinitions->NvRamMap);
2992 FreePool (FileFormTags->VariableDefinitions->FakeNvRamMap);
2993
2994 //
2995 // Allocate, copy the NvRamMap.
2996 //
2997 FileFormTags->VariableDefinitions->VariableFakeSize = (UINT16) (FileFormTags->VariableDefinitions->VariableFakeSize - FileFormTags->VariableDefinitions->VariableSize);
2998 FileFormTags->VariableDefinitions->VariableSize = (UINT16) NvMapSize;
2999 FileFormTags->VariableDefinitions->VariableFakeSize = (UINT16) (FileFormTags->VariableDefinitions->VariableFakeSize + FileFormTags->VariableDefinitions->VariableSize);
3000
3001 FileFormTags->VariableDefinitions->NvRamMap = AllocateZeroPool (FileFormTags->VariableDefinitions->VariableSize);
3002 ASSERT (FileFormTags->VariableDefinitions->NvRamMap != NULL);
3003
3004 FileFormTags->VariableDefinitions->FakeNvRamMap = AllocateZeroPool (NvMapSize + FileFormTags->VariableDefinitions->VariableFakeSize);
3005 ASSERT (FileFormTags->VariableDefinitions->FakeNvRamMap != NULL);
3006
3007 CopyMem (FileFormTags->VariableDefinitions->NvRamMap, NvMap, NvMapSize);
3008 FreePool (NvMapListHead);
3009 }
3010
3011 UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, TRUE);
3012 Repaint = TRUE;
3013 //
3014 // After the repaint operation, we should refresh the highlight.
3015 //
3016 NewLine = TRUE;
3017 break;
3018
3019 case CfUiNoOperation:
3020 ControlFlag = CfCheckSelection;
3021 break;
3022
3023 case CfExit:
3024 while (gMenuRefreshHead != NULL) {
3025 OldMenuRefreshEntry = gMenuRefreshHead->Next;
3026
3027 FreePool (gMenuRefreshHead);
3028
3029 gMenuRefreshHead = OldMenuRefreshEntry;
3030 }
3031
3032 gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4);
3033 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
3034 gST->ConOut->OutputString (gST->ConOut, (CHAR16 *) L"\n");
3035
3036 gActiveIfr = MenuOption->IfrNumber;
3037 return Selection;
3038
3039 default:
3040 break;
3041 }
3042 }
3043 }
3044
3045 BOOLEAN
3046 ValueIsScroll (
3047 IN BOOLEAN Direction,
3048 IN LIST_ENTRY *CurrentPos
3049 )
3050 /*++
3051
3052 Routine Description:
3053 Determine if the menu is the last menu that can be selected.
3054
3055 Arguments:
3056 Direction - the scroll direction. False is down. True is up.
3057
3058 Returns:
3059 FALSE -- the menu isn't the last menu that can be selected.
3060 TRUE -- the menu is the last menu that can be selected.
3061 --*/
3062 {
3063 LIST_ENTRY *Temp;
3064 UI_MENU_OPTION *MenuOption;
3065 MenuOption = NULL;
3066
3067 Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;
3068
3069 if (Temp == &Menu) {
3070 return TRUE;
3071 }
3072
3073 for (; Temp != &Menu; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) {
3074 MenuOption = CR (Temp, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
3075 if (!(MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut)) {
3076 return FALSE;
3077 }
3078 }
3079
3080 return TRUE;
3081 }
3082
3083 UINTN
3084 AdjustDateAndTimePosition (
3085 IN BOOLEAN DirectionUp,
3086 IN LIST_ENTRY **CurrentPosition
3087 )
3088 /*++
3089 Routine Description:
3090 Adjust Data and Time tag position accordingly.
3091 Data format : [01/02/2004] [11:22:33]
3092 Line number : 0 0 1 0 0 1
3093
3094 Arguments:
3095 Direction - the up or down direction. False is down. True is up.
3096 CurrentPos - Current position.
3097
3098 Returns:
3099 Return line number to pad. It is possible that we stand on a zero-advance
3100 data or time opcode, so pad one line when we judge if we are going to scroll outside.
3101 --*/
3102 {
3103 UINTN Count;
3104 LIST_ENTRY *NewPosition;
3105 UI_MENU_OPTION *MenuOption;
3106 UINTN PadLineNumber;
3107
3108 PadLineNumber = 0;
3109 NewPosition = *CurrentPosition;
3110 MenuOption = CR (NewPosition, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
3111
3112 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {
3113 //
3114 // Calculate the distance from current position to the last Date/Time op-code.
3115 //
3116 Count = 0;
3117 while (MenuOption->ThisTag->NumberOfLines == 0) {
3118 Count++;
3119 NewPosition = NewPosition->ForwardLink;
3120 MenuOption = CR (NewPosition, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
3121 PadLineNumber = 1;
3122 }
3123
3124 NewPosition = *CurrentPosition;
3125 if (DirectionUp) {
3126 //
3127 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended
3128 // to be one that back to the previous set of op-codes, we need to advance to the first
3129 // Date/Time op-code and leave the remaining logic in CfUiUp intact so the appropriate
3130 // checking can be done.
3131 //
3132 while (Count++ < 2) {
3133 NewPosition = NewPosition->BackLink;
3134 }
3135 } else {
3136 //
3137 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
3138 // to be one that progresses to the next set of op-codes, we need to advance to the last
3139 // Date/Time op-code and leave the remaining logic in CfUiDown intact so the appropriate
3140 // checking can be done.
3141 //
3142 while (Count-- > 0) {
3143 NewPosition = NewPosition->ForwardLink;
3144 }
3145 }
3146
3147 *CurrentPosition = NewPosition;
3148 }
3149
3150 return PadLineNumber;
3151 }