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