]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/BdsDxe/BootMaint/UpdatePage.c
Remove SafeFreePool from MemoryAllocationLib as this API's name is misleading. Its...
[mirror_edk2.git] / MdeModulePkg / Universal / BdsDxe / BootMaint / UpdatePage.c
1 /** @file
2 Dynamically update the pages.
3
4 Copyright (c) 2004 - 2008, Intel Corporation. <BR>
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 "BootMaint.h"
16
17 /**
18 Refresh the global UpdateData structure.
19
20 **/
21 VOID
22 RefreshUpdateData (
23 VOID
24 )
25 {
26 gUpdateData.Offset = 0;
27 }
28
29 /**
30 Add a "Go back to main page" tag in front of the form when there are no
31 "Apply changes" and "Discard changes" tags in the end of the form.
32
33 @param CallbackData The BMM context data.
34
35 **/
36 VOID
37 UpdatePageStart (
38 IN BMM_CALLBACK_DATA *CallbackData
39 )
40 {
41 RefreshUpdateData ();
42
43 if (!(CallbackData->BmmAskSaveOrNot)) {
44 //
45 // Add a "Go back to main page" tag in front of the form when there are no
46 // "Apply changes" and "Discard changes" tags in the end of the form.
47 //
48 CreateGotoOpCode (
49 FORM_MAIN_ID,
50 STRING_TOKEN (STR_FORM_GOTO_MAIN),
51 STRING_TOKEN (STR_FORM_GOTO_MAIN),
52 0,
53 FORM_MAIN_ID,
54 &gUpdateData
55 );
56 }
57
58 }
59
60 /**
61 Create the "Apply changes" and "Discard changes" tags. And
62 ensure user can return to the main page.
63
64 @param CallbackData The BMM context data.
65
66 **/
67 VOID
68 UpdatePageEnd (
69 IN BMM_CALLBACK_DATA *CallbackData
70 )
71 {
72 //
73 // Create the "Apply changes" and "Discard changes" tags.
74 //
75 if (CallbackData->BmmAskSaveOrNot) {
76 CreateSubTitleOpCode (
77 STRING_TOKEN (STR_NULL_STRING),
78 0,
79 0,
80 0,
81 &gUpdateData
82 );
83
84 CreateGotoOpCode (
85 FORM_MAIN_ID,
86 STRING_TOKEN (STR_SAVE_AND_EXIT),
87 STRING_TOKEN (STR_NULL_STRING),
88 EFI_IFR_FLAG_CALLBACK,
89 KEY_VALUE_SAVE_AND_EXIT,
90 &gUpdateData
91 );
92 }
93
94 //
95 // Ensure user can return to the main page.
96 //
97 CreateGotoOpCode (
98 FORM_MAIN_ID,
99 STRING_TOKEN (STR_NO_SAVE_AND_EXIT),
100 STRING_TOKEN (STR_NULL_STRING),
101 EFI_IFR_FLAG_CALLBACK,
102 KEY_VALUE_NO_SAVE_AND_EXIT,
103 &gUpdateData
104 );
105
106 IfrLibUpdateForm (
107 CallbackData->BmmHiiHandle,
108 &mBootMaintGuid,
109 CallbackData->BmmCurrentPageId,
110 CallbackData->BmmCurrentPageId,
111 FALSE,
112 &gUpdateData
113 );
114 }
115
116 /**
117 Clean up the dynamic opcode at label and form specified by
118 both LabelId.
119
120 @param LabelId It is both the Form ID and Label ID for
121 opcode deletion.
122 @param CallbackData The BMM context data.
123
124 **/
125 VOID
126 CleanUpPage (
127 IN UINT16 LabelId,
128 IN BMM_CALLBACK_DATA *CallbackData
129 )
130 {
131 RefreshUpdateData ();
132
133 //
134 // Remove all op-codes from dynamic page
135 //
136 IfrLibUpdateForm (
137 CallbackData->BmmHiiHandle,
138 &mBootMaintGuid,
139 LabelId,
140 LabelId,
141 FALSE,
142 &gUpdateData
143 );
144 }
145
146 /**
147 Boot a file selected by user at File Expoloer of BMM.
148
149 @param FileContext The file context data, which contains the device path
150 of the file to be boot from.
151
152 @retval EFI_SUCCESS The function completed successfull.
153 @return Other value if the boot from the file fails.
154
155 **/
156 EFI_STATUS
157 BootThisFile (
158 IN BM_FILE_CONTEXT *FileContext
159 )
160 {
161 EFI_STATUS Status;
162 UINTN ExitDataSize;
163 CHAR16 *ExitData;
164 BDS_COMMON_OPTION *Option;
165
166 Status = gBS->AllocatePool (EfiBootServicesData, sizeof (BDS_COMMON_OPTION), (VOID **) &Option);
167 Option->Description = FileContext->FileName;
168 Option->DevicePath = FileContext->DevicePath;
169 Option->LoadOptionsSize = 0;
170 Option->LoadOptions = NULL;
171
172 //
173 // Since current no boot from removable media directly is allowed */
174 //
175 gST->ConOut->ClearScreen (gST->ConOut);
176
177 ExitDataSize = 0;
178
179 Status = BdsLibBootViaBootOption (Option, Option->DevicePath, &ExitDataSize, &ExitData);
180
181 return Status;
182
183 }
184
185 /**
186 Create a list of Goto Opcode for all terminal devices logged
187 by TerminaMenu. This list will be inserted to form FORM_CON_COM_SETUP_ID.
188
189 @param CallbackData The BMM context data.
190 **/
191 VOID
192 UpdateConCOMPage (
193 IN BMM_CALLBACK_DATA *CallbackData
194 )
195 {
196 BM_MENU_ENTRY *NewMenuEntry;
197 UINT16 Index;
198
199 CallbackData->BmmAskSaveOrNot = FALSE;
200
201 UpdatePageStart (CallbackData);
202
203
204 for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
205 NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
206
207 CreateGotoOpCode (
208 FORM_CON_COM_SETUP_ID,
209 NewMenuEntry->DisplayStringToken,
210 STRING_TOKEN (STR_NULL_STRING),
211 EFI_IFR_FLAG_CALLBACK,
212 (UINT16) (TERMINAL_OPTION_OFFSET + Index),
213 &gUpdateData
214 );
215 }
216
217 UpdatePageEnd (CallbackData);
218 }
219
220 /**
221 Create a lit of boot option from global BootOptionMenu. It
222 allow user to delete the boot option.
223
224 @param CallbackData The BMM context data.
225
226 **/
227 VOID
228 UpdateBootDelPage (
229 IN BMM_CALLBACK_DATA *CallbackData
230 )
231 {
232 BM_MENU_ENTRY *NewMenuEntry;
233 BM_LOAD_CONTEXT *NewLoadContext;
234 UINT16 Index;
235
236 CallbackData->BmmAskSaveOrNot = TRUE;
237
238 UpdatePageStart (CallbackData);
239 CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, &BootOptionMenu);
240
241 for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
242 NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
243 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
244 if (NewLoadContext->IsLegacy) {
245 continue;
246 }
247
248 NewLoadContext->Deleted = FALSE;
249 CallbackData->BmmFakeNvData.BootOptionDel[Index] = 0x00;
250
251 CreateCheckBoxOpCode (
252 (EFI_QUESTION_ID) (BOOT_OPTION_DEL_QUESTION_ID + Index),
253 VARSTORE_ID_BOOT_MAINT,
254 (UINT16) (BOOT_OPTION_DEL_VAR_OFFSET + Index),
255 NewMenuEntry->DisplayStringToken,
256 NewMenuEntry->HelpStringToken,
257 0,
258 0,
259 &gUpdateData
260 );
261 }
262
263 UpdatePageEnd (CallbackData);
264 }
265
266 /**
267 Create a lit of driver option from global DriverMenu.
268
269 @param CallbackData The BMM context data.
270
271 **/
272 VOID
273 UpdateDrvAddHandlePage (
274 IN BMM_CALLBACK_DATA *CallbackData
275 )
276 {
277 BM_MENU_ENTRY *NewMenuEntry;
278 UINT16 Index;
279
280 CallbackData->BmmAskSaveOrNot = FALSE;
281
282 UpdatePageStart (CallbackData);
283
284 for (Index = 0; Index < DriverMenu.MenuNumber; Index++) {
285 NewMenuEntry = BOpt_GetMenuEntry (&DriverMenu, Index);
286
287 CreateGotoOpCode (
288 FORM_DRV_ADD_HANDLE_DESC_ID,
289 NewMenuEntry->DisplayStringToken,
290 STRING_TOKEN (STR_NULL_STRING),
291 EFI_IFR_FLAG_CALLBACK,
292 (UINT16) (HANDLE_OPTION_OFFSET + Index),
293 &gUpdateData
294 );
295 }
296
297 UpdatePageEnd (CallbackData);
298 }
299
300 /**
301 Create a lit of driver option from global DriverOptionMenu. It
302 allow user to delete the driver option.
303
304 @param CallbackData The BMM context data.
305
306 **/
307 VOID
308 UpdateDrvDelPage (
309 IN BMM_CALLBACK_DATA *CallbackData
310 )
311 {
312 BM_MENU_ENTRY *NewMenuEntry;
313 BM_LOAD_CONTEXT *NewLoadContext;
314 UINT16 Index;
315
316 CallbackData->BmmAskSaveOrNot = TRUE;
317
318 UpdatePageStart (CallbackData);
319
320 CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, &DriverOptionMenu);
321
322 for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
323 NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
324
325 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
326 NewLoadContext->Deleted = FALSE;
327 CallbackData->BmmFakeNvData.DriverOptionDel[Index] = 0x00;
328
329 CreateCheckBoxOpCode (
330 (EFI_QUESTION_ID) (DRIVER_OPTION_DEL_QUESTION_ID + Index),
331 VARSTORE_ID_BOOT_MAINT,
332 (UINT16) (DRIVER_OPTION_DEL_VAR_OFFSET + Index),
333 NewMenuEntry->DisplayStringToken,
334 NewMenuEntry->HelpStringToken,
335 0,
336 0,
337 &gUpdateData
338 );
339 }
340
341 UpdatePageEnd (CallbackData);
342 }
343
344 /**
345 Prepare the page to allow user to add description for
346 a Driver Option.
347
348 @param CallbackData The BMM context data.
349
350 **/
351 VOID
352 UpdateDriverAddHandleDescPage (
353 IN BMM_CALLBACK_DATA *CallbackData
354 )
355 {
356 BM_MENU_ENTRY *NewMenuEntry;
357
358 CallbackData->BmmFakeNvData.DriverAddActive = 0x01;
359 CallbackData->BmmFakeNvData.DriverAddForceReconnect = 0x00;
360 CallbackData->BmmAskSaveOrNot = TRUE;
361 NewMenuEntry = CallbackData->MenuEntry;
362
363 UpdatePageStart (CallbackData);
364
365 CreateSubTitleOpCode (
366 NewMenuEntry->DisplayStringToken,
367 0,
368 0,
369 0,
370 &gUpdateData
371 );
372
373 CreateStringOpCode (
374 (EFI_QUESTION_ID) DRV_ADD_HANDLE_DESC_QUESTION_ID,
375 VARSTORE_ID_BOOT_MAINT,
376 DRV_ADD_HANDLE_DESC_VAR_OFFSET,
377 STRING_TOKEN (STR_LOAD_OPTION_DESC),
378 STRING_TOKEN (STR_NULL_STRING),
379 0,
380 0,
381 6,
382 75,
383 &gUpdateData
384 );
385
386 CreateCheckBoxOpCode (
387 (EFI_QUESTION_ID) DRV_ADD_RECON_QUESTION_ID,
388 VARSTORE_ID_BOOT_MAINT,
389 DRV_ADD_RECON_VAR_OFFSET,
390 STRING_TOKEN (STR_LOAD_OPTION_FORCE_RECON),
391 STRING_TOKEN (STR_LOAD_OPTION_FORCE_RECON),
392 0,
393 0,
394 &gUpdateData
395 );
396
397 CreateStringOpCode (
398 (EFI_QUESTION_ID) DRIVER_ADD_OPTION_QUESTION_ID,
399 VARSTORE_ID_BOOT_MAINT,
400 DRIVER_ADD_OPTION_VAR_OFFSET,
401 STRING_TOKEN (STR_OPTIONAL_DATA),
402 STRING_TOKEN (STR_NULL_STRING),
403 0,
404 0,
405 6,
406 75,
407 &gUpdateData
408 );
409
410 UpdatePageEnd (CallbackData);
411 }
412
413 /**
414 Update console page.
415
416 @param UpdatePageId The form ID to be updated.
417 @param ConsoleMenu The console menu list.
418 @param CallbackData The BMM context data.
419
420 **/
421 VOID
422 UpdateConsolePage (
423 IN UINT16 UpdatePageId,
424 IN BM_MENU_OPTION *ConsoleMenu,
425 IN BMM_CALLBACK_DATA *CallbackData
426 )
427 {
428 BM_MENU_ENTRY *NewMenuEntry;
429 BM_CONSOLE_CONTEXT *NewConsoleContext;
430 BM_TERMINAL_CONTEXT *NewTerminalContext;
431 UINT16 Index;
432 UINT16 Index2;
433 UINT8 CheckFlags;
434
435 CallbackData->BmmAskSaveOrNot = TRUE;
436
437 UpdatePageStart (CallbackData);
438
439 for (Index = 0; Index < ConsoleMenu->MenuNumber; Index++) {
440 NewMenuEntry = BOpt_GetMenuEntry (ConsoleMenu, Index);
441 NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
442 CheckFlags = 0;
443 if (NewConsoleContext->IsActive) {
444 CheckFlags |= EFI_IFR_CHECKBOX_DEFAULT;
445 CallbackData->BmmFakeNvData.ConsoleCheck[Index] = TRUE;
446 } else {
447 CallbackData->BmmFakeNvData.ConsoleCheck[Index] = FALSE;
448 }
449
450 CreateCheckBoxOpCode (
451 (EFI_QUESTION_ID) (CON_DEVICE_QUESTION_ID + Index),
452 VARSTORE_ID_BOOT_MAINT,
453 (UINT16) (CON_DEVICE_VAR_OFFSET + Index),
454 NewMenuEntry->DisplayStringToken,
455 NewMenuEntry->HelpStringToken,
456 0,
457 CheckFlags,
458 &gUpdateData
459 );
460 }
461
462 for (Index2 = 0; Index2 < TerminalMenu.MenuNumber; Index2++) {
463 CheckFlags = 0;
464 NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index2);
465 NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
466
467 if (((NewTerminalContext->IsConIn != 0) && (UpdatePageId == FORM_CON_IN_ID)) ||
468 ((NewTerminalContext->IsConOut != 0) && (UpdatePageId == FORM_CON_OUT_ID)) ||
469 ((NewTerminalContext->IsStdErr != 0) && (UpdatePageId == FORM_CON_ERR_ID))
470 ) {
471 CheckFlags |= EFI_IFR_CHECKBOX_DEFAULT;
472 CallbackData->BmmFakeNvData.ConsoleCheck[Index] = TRUE;
473 } else {
474 CallbackData->BmmFakeNvData.ConsoleCheck[Index] = FALSE;
475 }
476
477 CreateCheckBoxOpCode (
478 (EFI_QUESTION_ID) (CON_DEVICE_QUESTION_ID + Index),
479 VARSTORE_ID_BOOT_MAINT,
480 (UINT16) (CON_DEVICE_VAR_OFFSET + Index),
481 NewMenuEntry->DisplayStringToken,
482 NewMenuEntry->HelpStringToken,
483 0,
484 CheckFlags,
485 &gUpdateData
486 );
487
488 Index++;
489 }
490
491 UpdatePageEnd (CallbackData);
492 }
493
494 /**
495 Update the page's NV Map if user has changed the order
496 a list. This list can be Boot Order or Driver Order.
497
498 @param UpdatePageId The form ID to be updated.
499 @param OptionMenu The new list.
500 @param CallbackData The BMM context data.
501
502 **/
503 VOID
504 UpdateOrderPage (
505 IN UINT16 UpdatePageId,
506 IN BM_MENU_OPTION *OptionMenu,
507 IN BMM_CALLBACK_DATA *CallbackData
508 )
509 {
510 BM_MENU_ENTRY *NewMenuEntry;
511 UINT16 Index;
512 IFR_OPTION *IfrOptionList;
513
514 CallbackData->BmmAskSaveOrNot = TRUE;
515
516 UpdatePageStart (CallbackData);
517
518 CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, OptionMenu);
519
520 ZeroMem (CallbackData->BmmFakeNvData.OptionOrder, 100);
521
522 IfrOptionList = AllocateZeroPool (sizeof (IFR_OPTION) * OptionMenu->MenuNumber);
523 if (NULL == IfrOptionList) {
524 return ;
525 }
526
527 for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
528 NewMenuEntry = BOpt_GetMenuEntry (OptionMenu, Index);
529 IfrOptionList[Index].StringToken = NewMenuEntry->DisplayStringToken;
530 IfrOptionList[Index].Value.u8 = (UINT8) (NewMenuEntry->OptionNumber + 1);
531 IfrOptionList[Index].Flags = 0;
532 CallbackData->BmmFakeNvData.OptionOrder[Index] = IfrOptionList[Index].Value.u8;
533 }
534
535 if (OptionMenu->MenuNumber > 0) {
536 CreateOrderedListOpCode (
537 (EFI_QUESTION_ID) OPTION_ORDER_QUESTION_ID,
538 VARSTORE_ID_BOOT_MAINT,
539 OPTION_ORDER_VAR_OFFSET,
540 STRING_TOKEN (STR_CHANGE_ORDER),
541 STRING_TOKEN (STR_CHANGE_ORDER),
542 0,
543 0,
544 EFI_IFR_NUMERIC_SIZE_1,
545 100,
546 IfrOptionList,
547 OptionMenu->MenuNumber,
548 &gUpdateData
549 );
550 }
551
552 FreePool (IfrOptionList);
553
554 UpdatePageEnd (CallbackData);
555
556 CopyMem (
557 CallbackData->BmmOldFakeNVData.OptionOrder,
558 CallbackData->BmmFakeNvData.OptionOrder,
559 100
560 );
561 }
562
563 /**
564 Create the dynamic page to allow user to set
565 the "BootNext" vaule.
566
567 @param CallbackData The BMM context data.
568
569 **/
570 VOID
571 UpdateBootNextPage (
572 IN BMM_CALLBACK_DATA *CallbackData
573 )
574 {
575 BM_MENU_ENTRY *NewMenuEntry;
576 BM_LOAD_CONTEXT *NewLoadContext;
577 IFR_OPTION *IfrOptionList;
578 UINTN NumberOfOptions;
579 UINT16 Index;
580
581 IfrOptionList = NULL;
582 NumberOfOptions = BootOptionMenu.MenuNumber;
583 CallbackData->BmmAskSaveOrNot = TRUE;
584
585 UpdatePageStart (CallbackData);
586 CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, &BootOptionMenu);
587
588 if (NumberOfOptions > 0) {
589 IfrOptionList = AllocateZeroPool ((NumberOfOptions + 1) * sizeof (IFR_OPTION));
590
591 ASSERT (IfrOptionList);
592
593 CallbackData->BmmFakeNvData.BootNext = (UINT16) (BootOptionMenu.MenuNumber);
594
595 for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
596 NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
597 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
598 if (NewLoadContext->IsBootNext) {
599 IfrOptionList[Index].Flags = EFI_IFR_OPTION_DEFAULT;
600 CallbackData->BmmFakeNvData.BootNext = Index;
601 } else {
602 IfrOptionList[Index].Flags = 0;
603 }
604
605 IfrOptionList[Index].Value.u16 = Index;
606 IfrOptionList[Index].StringToken = NewMenuEntry->DisplayStringToken;
607 }
608
609 IfrOptionList[Index].Value.u16 = Index;
610 IfrOptionList[Index].StringToken = STRING_TOKEN (STR_NONE);
611 IfrOptionList[Index].Flags = 0;
612 if (CallbackData->BmmFakeNvData.BootNext == Index) {
613 IfrOptionList[Index].Flags |= EFI_IFR_OPTION_DEFAULT;
614 }
615
616 CreateOneOfOpCode (
617 (EFI_QUESTION_ID) BOOT_NEXT_QUESTION_ID,
618 VARSTORE_ID_BOOT_MAINT,
619 BOOT_NEXT_VAR_OFFSET,
620 STRING_TOKEN (STR_BOOT_NEXT),
621 STRING_TOKEN (STR_BOOT_NEXT_HELP),
622 0,
623 EFI_IFR_NUMERIC_SIZE_2,
624 IfrOptionList,
625 (UINTN) (NumberOfOptions + 1),
626 &gUpdateData
627 );
628
629 FreePool (IfrOptionList);
630 }
631
632 UpdatePageEnd (CallbackData);
633 }
634
635 /**
636 Create the dynamic page to allow user to set
637 the "TimeOut" vaule.
638
639 @param CallbackData The BMM context data.
640
641 **/
642 VOID
643 UpdateTimeOutPage (
644 IN BMM_CALLBACK_DATA *CallbackData
645 )
646 {
647 UINT16 BootTimeOut;
648
649 CallbackData->BmmAskSaveOrNot = TRUE;
650
651 UpdatePageStart (CallbackData);
652
653 BootTimeOut = BdsLibGetTimeout ();
654
655 CreateNumericOpCode (
656 (EFI_QUESTION_ID) BOOT_TIME_OUT_QUESTION_ID,
657 VARSTORE_ID_BOOT_MAINT,
658 BOOT_TIME_OUT_VAR_OFFSET,
659 STRING_TOKEN (STR_NUM_AUTO_BOOT),
660 STRING_TOKEN (STR_HLP_AUTO_BOOT),
661 0,
662 EFI_IFR_NUMERIC_SIZE_2 | EFI_IFR_DISPLAY_UINT_DEC,
663 0,
664 65535,
665 0,
666 BootTimeOut,
667 &gUpdateData
668 );
669
670 CallbackData->BmmFakeNvData.BootTimeOut = BootTimeOut;
671
672 UpdatePageEnd (CallbackData);
673 }
674
675 /**
676 Refresh the text mode page
677
678 @param CallbackData The BMM context data.
679
680 **/
681 VOID
682 UpdateConModePage (
683 IN BMM_CALLBACK_DATA *CallbackData
684 )
685 {
686 UINTN Mode;
687 UINTN Index;
688 UINTN Col;
689 UINTN Row;
690 CHAR16 RowString[50];
691 CHAR16 ModeString[50];
692 UINTN MaxMode;
693 UINTN ValidMode;
694 EFI_STRING_ID *ModeToken;
695 IFR_OPTION *IfrOptionList;
696 EFI_STATUS Status;
697 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
698
699 ConOut = gST->ConOut;
700 Index = 0;
701 ValidMode = 0;
702 MaxMode = (UINTN) (ConOut->Mode->MaxMode);
703
704 CallbackData->BmmAskSaveOrNot = TRUE;
705
706 UpdatePageStart (CallbackData);
707
708 //
709 // Check valid mode
710 //
711 for (Mode = 0; Mode < MaxMode; Mode++) {
712 Status = ConOut->QueryMode (ConOut, Mode, &Col, &Row);
713 if (EFI_ERROR (Status)) {
714 continue;
715 }
716 ValidMode++;
717 }
718
719 if (ValidMode == 0) {
720 return;
721 }
722
723 IfrOptionList = AllocateZeroPool (sizeof (IFR_OPTION) * ValidMode);
724 ASSERT(IfrOptionList != NULL);
725
726 ModeToken = AllocateZeroPool (sizeof (EFI_STRING_ID) * ValidMode);
727 ASSERT(ModeToken != NULL);
728
729 //
730 // Determin which mode should be the first entry in menu
731 //
732 GetConsoleOutMode (CallbackData);
733
734 //
735 // Build text mode options
736 //
737 for (Mode = 0; Mode < MaxMode; Mode++) {
738 Status = ConOut->QueryMode (ConOut, Mode, &Col, &Row);
739 if (EFI_ERROR (Status)) {
740 continue;
741 }
742 //
743 // Build mode string Column x Row
744 //
745 UnicodeValueToString (ModeString, 0, Col, 0);
746 StrCat (ModeString, L" x ");
747 UnicodeValueToString (RowString, 0, Row, 0);
748 StrCat (ModeString, RowString);
749
750 HiiLibNewString (CallbackData->BmmHiiHandle, &ModeToken[Index], ModeString);
751
752 IfrOptionList[Index].StringToken = ModeToken[Index];
753 IfrOptionList[Index].Value.u16 = (UINT16) Mode;
754 if (Mode == CallbackData->BmmFakeNvData.ConsoleOutMode) {
755 IfrOptionList[Index].Flags = EFI_IFR_OPTION_DEFAULT;
756 } else {
757 IfrOptionList[Index].Flags = 0;
758 }
759 Index++;
760 }
761
762 CreateOneOfOpCode (
763 (EFI_QUESTION_ID) CON_MODE_QUESTION_ID,
764 VARSTORE_ID_BOOT_MAINT,
765 CON_MODE_VAR_OFFSET,
766 STRING_TOKEN (STR_CON_MODE_SETUP),
767 STRING_TOKEN (STR_CON_MODE_SETUP),
768 EFI_IFR_FLAG_RESET_REQUIRED,
769 EFI_IFR_NUMERIC_SIZE_2,
770 IfrOptionList,
771 ValidMode,
772 &gUpdateData
773 );
774 FreePool (IfrOptionList);
775 FreePool (ModeToken);
776
777 UpdatePageEnd (CallbackData);
778 }
779
780 /**
781 Create the dynamic page which allows user to
782 set the property such as Baud Rate, Data Bits,
783 Parity, Stop Bits, Terminal Type.
784
785 @param CallbackData The BMM context data.
786
787 **/
788 VOID
789 UpdateTerminalPage (
790 IN BMM_CALLBACK_DATA *CallbackData
791 )
792 {
793 UINT8 Index;
794 UINT8 CheckFlags;
795 IFR_OPTION *IfrOptionList;
796 BM_MENU_ENTRY *NewMenuEntry;
797 BM_TERMINAL_CONTEXT *NewTerminalContext;
798
799 CallbackData->BmmAskSaveOrNot = TRUE;
800
801 UpdatePageStart (CallbackData);
802
803 NewMenuEntry = BOpt_GetMenuEntry (
804 &TerminalMenu,
805 CallbackData->CurrentTerminal
806 );
807
808 if (NewMenuEntry == NULL) {
809 return ;
810 }
811
812 NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
813
814 IfrOptionList = AllocateZeroPool (sizeof (IFR_OPTION) * 19);
815 if (IfrOptionList == NULL) {
816 return ;
817 }
818
819 for (Index = 0; Index < sizeof (BaudRateList) / sizeof (BaudRateList [0]); Index++) {
820 CheckFlags = 0;
821 if (NewTerminalContext->BaudRate == (UINT64) (BaudRateList[Index].Value)) {
822 CheckFlags |= EFI_IFR_OPTION_DEFAULT;
823 NewTerminalContext->BaudRateIndex = Index;
824 CallbackData->BmmFakeNvData.COMBaudRate = NewTerminalContext->BaudRateIndex;
825 }
826
827 IfrOptionList[Index].Flags = CheckFlags;
828 IfrOptionList[Index].StringToken = BaudRateList[Index].StringToken;
829 IfrOptionList[Index].Value.u8 = Index;
830 }
831
832 CreateOneOfOpCode (
833 (EFI_QUESTION_ID) COM_BAUD_RATE_QUESTION_ID,
834 VARSTORE_ID_BOOT_MAINT,
835 COM_BAUD_RATE_VAR_OFFSET,
836 STRING_TOKEN (STR_COM_BAUD_RATE),
837 STRING_TOKEN (STR_COM_BAUD_RATE),
838 0,
839 EFI_IFR_NUMERIC_SIZE_1,
840 IfrOptionList,
841 19,
842 &gUpdateData
843 );
844
845 for (Index = 0; Index < sizeof (DataBitsList) / sizeof (DataBitsList[0]); Index++) {
846 CheckFlags = 0;
847
848 if (NewTerminalContext->DataBits == DataBitsList[Index].Value) {
849 NewTerminalContext->DataBitsIndex = Index;
850 CallbackData->BmmFakeNvData.COMDataRate = NewTerminalContext->DataBitsIndex;
851 CheckFlags |= EFI_IFR_OPTION_DEFAULT;
852 }
853
854 IfrOptionList[Index].Flags = CheckFlags;
855 IfrOptionList[Index].StringToken = DataBitsList[Index].StringToken;
856 IfrOptionList[Index].Value.u8 = Index;
857 }
858
859 CreateOneOfOpCode (
860 (EFI_QUESTION_ID) COM_DATA_RATE_QUESTION_ID,
861 VARSTORE_ID_BOOT_MAINT,
862 COM_DATA_RATE_VAR_OFFSET,
863 STRING_TOKEN (STR_COM_DATA_BITS),
864 STRING_TOKEN (STR_COM_DATA_BITS),
865 0,
866 EFI_IFR_NUMERIC_SIZE_1,
867 IfrOptionList,
868 4,
869 &gUpdateData
870 );
871
872 for (Index = 0; Index < sizeof (ParityList) / sizeof (ParityList[0]); Index++) {
873 CheckFlags = 0;
874 if (NewTerminalContext->Parity == ParityList[Index].Value) {
875 CheckFlags |= EFI_IFR_OPTION_DEFAULT;
876 NewTerminalContext->ParityIndex = (UINT8) Index;
877 CallbackData->BmmFakeNvData.COMParity = NewTerminalContext->ParityIndex;
878 }
879
880 IfrOptionList[Index].Flags = CheckFlags;
881 IfrOptionList[Index].StringToken = ParityList[Index].StringToken;
882 IfrOptionList[Index].Value.u8 = Index;
883 }
884
885 CreateOneOfOpCode (
886 (EFI_QUESTION_ID) COM_PARITY_QUESTION_ID,
887 VARSTORE_ID_BOOT_MAINT,
888 COM_PARITY_VAR_OFFSET,
889 STRING_TOKEN (STR_COM_PARITY),
890 STRING_TOKEN (STR_COM_PARITY),
891 0,
892 EFI_IFR_NUMERIC_SIZE_1,
893 IfrOptionList,
894 5,
895 &gUpdateData
896 );
897
898 for (Index = 0; Index < sizeof (StopBitsList) / sizeof (StopBitsList[0]); Index++) {
899 CheckFlags = 0;
900 if (NewTerminalContext->StopBits == StopBitsList[Index].Value) {
901 CheckFlags |= EFI_IFR_OPTION_DEFAULT;
902 NewTerminalContext->StopBitsIndex = (UINT8) Index;
903 CallbackData->BmmFakeNvData.COMStopBits = NewTerminalContext->StopBitsIndex;
904 }
905
906 IfrOptionList[Index].Flags = CheckFlags;
907 IfrOptionList[Index].StringToken = StopBitsList[Index].StringToken;
908 IfrOptionList[Index].Value.u8 = Index;
909 }
910
911 CreateOneOfOpCode (
912 (EFI_QUESTION_ID) COM_STOP_BITS_QUESTION_ID,
913 VARSTORE_ID_BOOT_MAINT,
914 COM_STOP_BITS_VAR_OFFSET,
915 STRING_TOKEN (STR_COM_STOP_BITS),
916 STRING_TOKEN (STR_COM_STOP_BITS),
917 0,
918 EFI_IFR_NUMERIC_SIZE_1,
919 IfrOptionList,
920 3,
921 &gUpdateData
922 );
923
924 for (Index = 0; Index < 4; Index++) {
925 CheckFlags = 0;
926 if (NewTerminalContext->TerminalType == Index) {
927 CheckFlags |= EFI_IFR_OPTION_DEFAULT;
928 CallbackData->BmmFakeNvData.COMTerminalType = NewTerminalContext->TerminalType;
929 }
930
931 IfrOptionList[Index].Flags = CheckFlags;
932 IfrOptionList[Index].StringToken = (EFI_STRING_ID) TerminalType[Index];
933 IfrOptionList[Index].Value.u8 = Index;
934 }
935
936 CreateOneOfOpCode (
937 (EFI_QUESTION_ID) COM_TERMINAL_QUESTION_ID,
938 VARSTORE_ID_BOOT_MAINT,
939 COM_TERMINAL_VAR_OFFSET,
940 STRING_TOKEN (STR_COM_TERMI_TYPE),
941 STRING_TOKEN (STR_COM_TERMI_TYPE),
942 0,
943 EFI_IFR_NUMERIC_SIZE_1,
944 IfrOptionList,
945 4,
946 &gUpdateData
947 );
948
949 FreePool (IfrOptionList);
950
951 UpdatePageEnd (CallbackData);
952 }
953
954 /**
955 Dispatch the correct update page function to call based on
956 the UpdatePageId.
957
958 @param UpdatePageId The form ID.
959 @param CallbackData The BMM context data.
960
961 **/
962 VOID
963 UpdatePageBody (
964 IN UINT16 UpdatePageId,
965 IN BMM_CALLBACK_DATA *CallbackData
966 )
967 {
968 CleanUpPage (UpdatePageId, CallbackData);
969 switch (UpdatePageId) {
970 case FORM_CON_IN_ID:
971 UpdateConsolePage (UpdatePageId, &ConsoleInpMenu, CallbackData);
972 break;
973
974 case FORM_CON_OUT_ID:
975 UpdateConsolePage (UpdatePageId, &ConsoleOutMenu, CallbackData);
976 break;
977
978 case FORM_CON_ERR_ID:
979 UpdateConsolePage (UpdatePageId, &ConsoleErrMenu, CallbackData);
980 break;
981
982 case FORM_BOOT_CHG_ID:
983 UpdateOrderPage (UpdatePageId, &BootOptionMenu, CallbackData);
984 break;
985
986 case FORM_DRV_CHG_ID:
987 UpdateOrderPage (UpdatePageId, &DriverOptionMenu, CallbackData);
988 break;
989
990 default:
991 break;
992 }
993 }
994
995 /**
996 Get the index number (#### in Boot####) for the boot option pointed to a BBS legacy device type
997 specified by DeviceType.
998
999 @param DeviceType The legacy device type. It can be floppy, network, harddisk, cdrom,
1000 etc.
1001 @param OptionIndex Returns the index number (#### in Boot####).
1002 @param OptionSize Return the size of the Boot### variable.
1003
1004 **/
1005 VOID *
1006 GetLegacyBootOptionVar (
1007 IN UINTN DeviceType,
1008 OUT UINTN *OptionIndex,
1009 OUT UINTN *OptionSize
1010 )
1011 {
1012 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1013 VOID *OptionBuffer;
1014 UINTN OrderSize;
1015 UINTN Index;
1016 UINT16 *OrderBuffer;
1017 CHAR16 StrTemp[100];
1018 UINT16 FilePathSize;
1019 UINT8 *Ptr;
1020 UINT8 *OptionalData;
1021
1022 //
1023 // Get Boot Option number from the size of BootOrder
1024 //
1025 OrderBuffer = BdsLibGetVariableAndSize (
1026 L"BootOrder",
1027 &gEfiGlobalVariableGuid,
1028 &OrderSize
1029 );
1030
1031 for (Index = 0; Index < OrderSize / sizeof (UINT16); Index++) {
1032 UnicodeSPrint (StrTemp, 100, L"Boot%04x", OrderBuffer[Index]);
1033 OptionBuffer = BdsLibGetVariableAndSize (
1034 StrTemp,
1035 &gEfiGlobalVariableGuid,
1036 OptionSize
1037 );
1038 if (NULL == OptionBuffer) {
1039 continue;
1040 }
1041
1042 Ptr = (UINT8 *) OptionBuffer;
1043 Ptr += sizeof (UINT32);
1044
1045 FilePathSize = *(UINT16 *) Ptr;
1046 Ptr += sizeof (UINT16);
1047
1048 Ptr += StrSize ((CHAR16 *) Ptr);
1049
1050 //
1051 // Now Ptr point to Device Path
1052 //
1053 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
1054 Ptr += FilePathSize;
1055
1056 //
1057 // Now Ptr point to Optional Data
1058 //
1059 OptionalData = Ptr;
1060
1061 if ((DeviceType == ((BBS_TABLE *) OptionalData)->DeviceType) &&
1062 (BBS_DEVICE_PATH == DevicePath->Type) &&
1063 (BBS_BBS_DP == DevicePath->SubType)
1064 ) {
1065 *OptionIndex = OrderBuffer[Index];
1066 FreePool (OrderBuffer);
1067 return OptionBuffer;
1068 } else {
1069 FreePool (OptionBuffer);
1070 }
1071 }
1072
1073 FreePool (OrderBuffer);
1074 return NULL;
1075 }
1076
1077 /**
1078 Create a dynamic page so that Legacy Device boot order
1079 can be set for specified device type.
1080
1081 @param UpdatePageId The form ID. It also spefies the legacy device type.
1082 @param CallbackData The BMM context data.
1083
1084
1085 **/
1086 VOID
1087 UpdateSetLegacyDeviceOrderPage (
1088 IN UINT16 UpdatePageId,
1089 IN BMM_CALLBACK_DATA *CallbackData
1090 )
1091 {
1092 BM_LEGACY_DEV_ORDER_CONTEXT *DevOrder;
1093 BM_MENU_OPTION *OptionMenu;
1094 BM_MENU_ENTRY *NewMenuEntry;
1095 IFR_OPTION *IfrOptionList;
1096 EFI_STRING_ID StrRef;
1097 EFI_STRING_ID StrRefHelp;
1098 BBS_TYPE BbsType;
1099 UINTN VarSize;
1100 UINTN Pos;
1101 UINTN Bit;
1102 UINT16 Index;
1103 UINT16 Key;
1104 CHAR16 String[100];
1105 CHAR16 *TypeStr;
1106 CHAR16 *TypeStrHelp;
1107 UINT16 VarDevOrder;
1108 UINT8 *VarData;
1109 UINT8 *LegacyOrder;
1110 UINT8 *OldData;
1111 UINT8 *DisMap;
1112
1113 OptionMenu = NULL;
1114 Key = 0;
1115 StrRef = 0;
1116 StrRefHelp = 0;
1117 TypeStr = NULL;
1118 TypeStrHelp = NULL;
1119 BbsType = BBS_FLOPPY;
1120 LegacyOrder = NULL;
1121 OldData = NULL;
1122 DisMap = NULL;
1123
1124 CallbackData->BmmAskSaveOrNot = TRUE;
1125 UpdatePageStart (CallbackData);
1126
1127 DisMap = CallbackData->BmmOldFakeNVData.DisableMap;
1128
1129 SetMem (DisMap, 32, 0);
1130 //
1131 // Create oneof option list
1132 //
1133 switch (UpdatePageId) {
1134 case FORM_SET_FD_ORDER_ID:
1135 OptionMenu = (BM_MENU_OPTION *) &LegacyFDMenu;
1136 Key = (UINT16) LEGACY_FD_QUESTION_ID;
1137 TypeStr = STR_FLOPPY;
1138 TypeStrHelp = STR_FLOPPY_HELP;
1139 BbsType = BBS_FLOPPY;
1140 LegacyOrder = CallbackData->BmmFakeNvData.LegacyFD;
1141 OldData = CallbackData->BmmOldFakeNVData.LegacyFD;
1142 break;
1143
1144 case FORM_SET_HD_ORDER_ID:
1145 OptionMenu = (BM_MENU_OPTION *) &LegacyHDMenu;
1146 Key = (UINT16) LEGACY_HD_QUESTION_ID;
1147 TypeStr = STR_HARDDISK;
1148 TypeStrHelp = STR_HARDDISK_HELP;
1149 BbsType = BBS_HARDDISK;
1150 LegacyOrder = CallbackData->BmmFakeNvData.LegacyHD;
1151 OldData = CallbackData->BmmOldFakeNVData.LegacyHD;
1152 break;
1153
1154 case FORM_SET_CD_ORDER_ID:
1155 OptionMenu = (BM_MENU_OPTION *) &LegacyCDMenu;
1156 Key = (UINT16) LEGACY_CD_QUESTION_ID;
1157 TypeStr = STR_CDROM;
1158 TypeStrHelp = STR_CDROM_HELP;
1159 BbsType = BBS_CDROM;
1160 LegacyOrder = CallbackData->BmmFakeNvData.LegacyCD;
1161 OldData = CallbackData->BmmOldFakeNVData.LegacyCD;
1162 break;
1163
1164 case FORM_SET_NET_ORDER_ID:
1165 OptionMenu = (BM_MENU_OPTION *) &LegacyNETMenu;
1166 Key = (UINT16) LEGACY_NET_QUESTION_ID;
1167 TypeStr = STR_NET;
1168 TypeStrHelp = STR_NET_HELP;
1169 BbsType = BBS_EMBED_NETWORK;
1170 LegacyOrder = CallbackData->BmmFakeNvData.LegacyNET;
1171 OldData = CallbackData->BmmOldFakeNVData.LegacyNET;
1172 break;
1173
1174 case FORM_SET_BEV_ORDER_ID:
1175 OptionMenu = (BM_MENU_OPTION *) &LegacyBEVMenu;
1176 Key = (UINT16) LEGACY_BEV_QUESTION_ID;
1177 TypeStr = STR_BEV;
1178 TypeStrHelp = STR_BEV_HELP;
1179 BbsType = BBS_BEV_DEVICE;
1180 LegacyOrder = CallbackData->BmmFakeNvData.LegacyBEV;
1181 OldData = CallbackData->BmmOldFakeNVData.LegacyBEV;
1182 break;
1183
1184 }
1185
1186 CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, OptionMenu);
1187
1188 IfrOptionList = AllocateZeroPool (sizeof (IFR_OPTION) * (OptionMenu->MenuNumber + 1));
1189 if (NULL == IfrOptionList) {
1190 return ;
1191 }
1192
1193 for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
1194 NewMenuEntry = BOpt_GetMenuEntry (OptionMenu, Index);
1195 IfrOptionList[Index].Flags = 0;
1196 if (0 == Index) {
1197 IfrOptionList[Index].Flags |= EFI_IFR_OPTION_DEFAULT;
1198 }
1199
1200 IfrOptionList[Index].StringToken = NewMenuEntry->DisplayStringToken;
1201 IfrOptionList[Index].Value.u8 = (UINT8) ((BM_LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext)->Index;
1202 }
1203 //
1204 // for item "Disabled"
1205 //
1206 IfrOptionList[Index].Flags = 0;
1207 IfrOptionList[Index].StringToken = STRING_TOKEN (STR_DISABLE_LEGACY_DEVICE);
1208 IfrOptionList[Index].Value.u8 = 0xFF;
1209
1210 //
1211 // Get Device Order from variable
1212 //
1213 VarData = BdsLibGetVariableAndSize (
1214 VAR_LEGACY_DEV_ORDER,
1215 &EfiLegacyDevOrderGuid,
1216 &VarSize
1217 );
1218
1219 if (NULL != VarData) {
1220 DevOrder = (BM_LEGACY_DEV_ORDER_CONTEXT *) VarData;
1221 while (VarData < VarData + VarSize) {
1222 if (DevOrder->BbsType == BbsType) {
1223 break;
1224 }
1225
1226 VarData += sizeof (BBS_TYPE);
1227 VarData += *(UINT16 *) VarData;
1228 DevOrder = (BM_LEGACY_DEV_ORDER_CONTEXT *) VarData;
1229 }
1230 //
1231 // Create oneof tag here for FD/HD/CD #1 #2
1232 //
1233 for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
1234 //
1235 // Create the string for oneof tag
1236 //
1237 UnicodeSPrint (String, sizeof (String), TypeStr, Index);
1238 StrRef = 0;
1239 HiiLibNewString (CallbackData->BmmHiiHandle, &StrRef, String);
1240
1241 UnicodeSPrint (String, sizeof (String), TypeStrHelp, Index);
1242 StrRefHelp = 0;
1243 HiiLibNewString (CallbackData->BmmHiiHandle, &StrRefHelp, String);
1244
1245 CreateOneOfOpCode (
1246 (EFI_QUESTION_ID) (Key + Index),
1247 VARSTORE_ID_BOOT_MAINT,
1248 (UINT16) (Key + Index - CONFIG_OPTION_OFFSET),
1249 StrRef,
1250 StrRefHelp,
1251 EFI_IFR_FLAG_CALLBACK,
1252 EFI_IFR_NUMERIC_SIZE_1,
1253 IfrOptionList,
1254 OptionMenu->MenuNumber + 1,
1255 &gUpdateData
1256 );
1257
1258 VarDevOrder = *(UINT16 *) ((UINT8 *) DevOrder + sizeof (BBS_TYPE) + sizeof (UINT16) + Index * sizeof (UINT16));
1259
1260 if (0xFF00 == (VarDevOrder & 0xFF00)) {
1261 LegacyOrder[Index] = 0xFF;
1262 Pos = (VarDevOrder & 0xFF) / 8;
1263 Bit = 7 - ((VarDevOrder & 0xFF) % 8);
1264 DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
1265 } else {
1266 LegacyOrder[Index] = (UINT8) (VarDevOrder & 0xFF);
1267 }
1268 }
1269 }
1270
1271 CopyMem (OldData, LegacyOrder, 100);
1272
1273 if (IfrOptionList != NULL) {
1274 FreePool (IfrOptionList);
1275 IfrOptionList = NULL;
1276 }
1277
1278 UpdatePageEnd (CallbackData);
1279 }
1280
1281 /**
1282 Dispatch the display to the next page based on NewPageId.
1283
1284 @param Private The BMM context data.
1285 @param NewPageId The original page ID.
1286
1287 **/
1288 VOID
1289 UpdatePageId (
1290 BMM_CALLBACK_DATA *Private,
1291 UINT16 NewPageId
1292 )
1293 {
1294 if ((NewPageId < FILE_OPTION_OFFSET) && (NewPageId >= HANDLE_OPTION_OFFSET)) {
1295 //
1296 // If we select a handle to add driver option, advance to the add handle description page.
1297 //
1298 NewPageId = FORM_DRV_ADD_HANDLE_DESC_ID;
1299 } else if ((NewPageId == KEY_VALUE_SAVE_AND_EXIT) || (NewPageId == KEY_VALUE_NO_SAVE_AND_EXIT)) {
1300 //
1301 // Return to main page after "Save Changes" or "Discard Changes".
1302 //
1303 NewPageId = FORM_MAIN_ID;
1304 } else if ((NewPageId >= TERMINAL_OPTION_OFFSET) && (NewPageId < CONSOLE_OPTION_OFFSET)) {
1305 NewPageId = FORM_CON_COM_SETUP_ID;
1306 }
1307
1308 if ((NewPageId > 0) && (NewPageId < MAXIMUM_FORM_ID)) {
1309 Private->BmmPreviousPageId = Private->BmmCurrentPageId;
1310 Private->BmmCurrentPageId = NewPageId;
1311 }
1312 }