]> git.proxmox.com Git - mirror_edk2.git/blame - MdePkg/Library/IfrSupportLib/UefiIfrForm.c
MdePkg/Library/IfrSupportLib/UefiIfrForm.c:
[mirror_edk2.git] / MdePkg / Library / IfrSupportLib / UefiIfrForm.c
CommitLineData
e52c5a9f 1/** @file
2
3Copyright (c) 2007, Intel Corporation
4All rights reserved. This program and the accompanying materials
5are licensed and made available under the terms and conditions of the BSD License
6which accompanies this distribution. The full text of the license may be found at
7http://opensource.org/licenses/bsd-license.php
8
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12Module Name:
13
14 UefiIfrForm.c
15
16Abstract:
17
18 Common Library Routines to assist handle HII elements.
19
20
21**/
22
23#include "UefiIfrLibraryInternal.h"
24
25//
26// Fake <ConfigHdr>
27//
28UINT16 mFakeConfigHdr[] = L"GUID=00000000000000000000000000000000&NAME=0000&PATH=0";
29
168f4233 30#if 0
e52c5a9f 31STATIC
32EFI_STATUS
33GetPackageDataFromPackageList (
34 IN EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList,
35 IN UINT32 PackageIndex,
36 OUT UINT32 *BufferLen,
37 OUT EFI_HII_PACKAGE_HEADER **Buffer
38 )
39{
40 UINT32 Index;
41 EFI_HII_PACKAGE_HEADER *Package;
42 UINT32 Offset;
43 UINT32 PackageListLength;
44 EFI_HII_PACKAGE_HEADER PackageHeader = {0, 0};
45
46 ASSERT(HiiPackageList != NULL);
47
48 if ((BufferLen == NULL) || (Buffer == NULL)) {
49 return EFI_INVALID_PARAMETER;
50 }
51
52 Package = NULL;
53 Index = 0;
54 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
55 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
56 while (Offset < PackageListLength) {
57 Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset);
58 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
59 if (Index == PackageIndex) {
60 break;
61 }
62 Offset += PackageHeader.Length;
63 Index++;
64 }
65 if (Offset >= PackageListLength) {
66 //
67 // no package found in this Package List
68 //
69 return EFI_NOT_FOUND;
70 }
71
72 *BufferLen = PackageHeader.Length;
73 *Buffer = Package;
74 return EFI_SUCCESS;
75}
168f4233 76#endif
e52c5a9f 77
78
79/**
80 Draw a dialog and return the selected key.
81
82 @param NumberOfLines The number of lines for the dialog box
83 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..
84 @param String Pointer to the first string in the list
85 @param ... A series of (quantity == NumberOfLines) text
86 strings which will be used to construct the dialog
87 box
88
89 @retval EFI_SUCCESS Displayed dialog and received user interaction
90 @retval EFI_INVALID_PARAMETER One of the parameters was invalid.
91
92**/
93EFI_STATUS
94EFIAPI
95IfrLibCreatePopUp (
96 IN UINTN NumberOfLines,
97 OUT EFI_INPUT_KEY *KeyValue,
98 IN CHAR16 *String,
99 ...
100 )
101{
102 UINTN Index;
103 UINTN Count;
104 UINTN Start;
105 UINTN Top;
106 CHAR16 *StringPtr;
107 UINTN LeftColumn;
108 UINTN RightColumn;
109 UINTN TopRow;
110 UINTN BottomRow;
111 UINTN DimensionsWidth;
112 UINTN DimensionsHeight;
113 VA_LIST Marker;
114 EFI_INPUT_KEY Key;
115 UINTN LargestString;
116 CHAR16 *StackString;
117 EFI_STATUS Status;
118 UINTN StringLen;
119 CHAR16 *LineBuffer;
120 CHAR16 **StringArray;
121 EFI_EVENT TimerEvent;
122 EFI_EVENT WaitList[2];
123 UINTN CurrentAttribute;
124 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
125
126 if ((KeyValue == NULL) || (String == NULL)) {
127 return EFI_INVALID_PARAMETER;
128 }
129
130 TopRow = 0;
131 BottomRow = 0;
132 LeftColumn = 0;
133 RightColumn = 0;
134
135 ConOut = gST->ConOut;
136 ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &RightColumn, &BottomRow);
137
138 DimensionsWidth = RightColumn - LeftColumn;
139 DimensionsHeight = BottomRow - TopRow;
140
141 CurrentAttribute = ConOut->Mode->Attribute;
142
143 LineBuffer = AllocateZeroPool (DimensionsWidth * sizeof (CHAR16));
144 ASSERT (LineBuffer != NULL);
145
146 //
147 // Determine the largest string in the dialog box
148 // Notice we are starting with 1 since String is the first string
149 //
150 StringArray = AllocateZeroPool (NumberOfLines * sizeof (CHAR16 *));
151 LargestString = StrLen (String);
152 StringArray[0] = String;
153
154 VA_START (Marker, String);
155 for (Index = 1; Index < NumberOfLines; Index++) {
156 StackString = VA_ARG (Marker, CHAR16 *);
157
158 if (StackString == NULL) {
159 return EFI_INVALID_PARAMETER;
160 }
161
162 StringArray[Index] = StackString;
163 StringLen = StrLen (StackString);
164 if (StringLen > LargestString) {
165 LargestString = StringLen;
166 }
167 }
168
169 if ((LargestString + 2) > DimensionsWidth) {
170 LargestString = DimensionsWidth - 2;
171 }
172
173 //
174 // Subtract the PopUp width from total Columns, allow for one space extra on
175 // each end plus a border.
176 //
177 Start = (DimensionsWidth - LargestString - 2) / 2 + LeftColumn + 1;
178
179 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + TopRow - 1;
180
181 //
182 // Disable cursor
183 //
184 ConOut->EnableCursor (ConOut, FALSE);
185 ConOut->SetAttribute (ConOut, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
186
187 StringPtr = &LineBuffer[0];
188 *StringPtr++ = BOXDRAW_DOWN_RIGHT;
189 for (Index = 0; Index < LargestString; Index++) {
190 *StringPtr++ = BOXDRAW_HORIZONTAL;
191 }
192 *StringPtr++ = BOXDRAW_DOWN_LEFT;
193 *StringPtr = L'\0';
194
195 ConOut->SetCursorPosition (ConOut, Start, Top);
196 ConOut->OutputString (ConOut, LineBuffer);
197
198 for (Index = 0; Index < NumberOfLines; Index++) {
199 StringPtr = &LineBuffer[0];
200 *StringPtr++ = BOXDRAW_VERTICAL;
201
202 for (Count = 0; Count < LargestString; Count++) {
203 StringPtr[Count] = L' ';
204 }
205
206 StringLen = StrLen (StringArray[Index]);
207 if (StringLen > LargestString) {
208 StringLen = LargestString;
209 }
210 CopyMem (
211 StringPtr + ((LargestString - StringLen) / 2),
212 StringArray[Index],
213 StringLen * sizeof (CHAR16)
214 );
215 StringPtr += LargestString;
216
217 *StringPtr++ = BOXDRAW_VERTICAL;
218 *StringPtr = L'\0';
219
220 ConOut->SetCursorPosition (ConOut, Start, Top + 1 + Index);
221 ConOut->OutputString (ConOut, LineBuffer);
222 }
223
224 StringPtr = &LineBuffer[0];
225 *StringPtr++ = BOXDRAW_UP_RIGHT;
226 for (Index = 0; Index < LargestString; Index++) {
227 *StringPtr++ = BOXDRAW_HORIZONTAL;
228 }
229 *StringPtr++ = BOXDRAW_UP_LEFT;
230 *StringPtr = L'\0';
231
232 ConOut->SetCursorPosition (ConOut, Start, Top + NumberOfLines + 1);
233 ConOut->OutputString (ConOut, LineBuffer);
234
235 do {
236 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
237
238 //
239 // Set a timer event of 1 second expiration
240 //
241 gBS->SetTimer (
242 TimerEvent,
243 TimerRelative,
244 10000000
245 );
246
247 //
248 // Wait for the keystroke event or the timer
249 //
250 WaitList[0] = gST->ConIn->WaitForKey;
251 WaitList[1] = TimerEvent;
252 Status = gBS->WaitForEvent (2, WaitList, &Index);
253
254 //
255 // Check for the timer expiration
256 //
257 if (!EFI_ERROR (Status) && Index == 1) {
258 Status = EFI_TIMEOUT;
259 }
260
261 gBS->CloseEvent (TimerEvent);
262 } while (Status == EFI_TIMEOUT);
263
264 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
265 CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));
266
267 ConOut->SetAttribute (ConOut, CurrentAttribute);
268 ConOut->EnableCursor (ConOut, TRUE);
269
270 return Status;
271}
272
273
274/**
275 Swap bytes in the buffer.
276
277 @param Buffer Binary buffer.
278 @param BufferSize Size of the buffer in bytes.
279
280 @return None.
281
282**/
283STATIC
284VOID
285SwapBuffer (
286 IN OUT UINT8 *Buffer,
287 IN UINTN BufferSize
288 )
289{
290 UINTN Index;
291 UINT8 Temp;
292 UINTN SwapCount;
293
294 SwapCount = (BufferSize - 1) / 2;
295 for (Index = 0; Index < SwapCount; Index++) {
296 Temp = Buffer[Index];
297 Buffer[Index] = Buffer[BufferSize - 1 - Index];
298 Buffer[BufferSize - 1 - Index] = Temp;
299 }
300}
301
302
303/**
304 Converts binary buffer to Unicode string in reversed byte order from R8_BufToHexString().
305
306 @param Str String for output
307 @param Buffer Binary buffer.
308 @param BufferSize Size of the buffer in bytes.
309
310 @retval EFI_SUCCESS The function completed successfully.
311
312**/
313EFI_STATUS
314EFIAPI
315BufferToHexString (
316 IN OUT CHAR16 *Str,
317 IN UINT8 *Buffer,
318 IN UINTN BufferSize
319 )
320{
321 EFI_STATUS Status;
322 UINT8 *NewBuffer;
323 UINTN StrBufferLen;
324
325 NewBuffer = AllocateCopyPool (BufferSize, Buffer);
326 SwapBuffer (NewBuffer, BufferSize);
327
328 StrBufferLen = (BufferSize + 1) * sizeof (CHAR16);
329 Status = R8_BufToHexString (Str, &StrBufferLen, NewBuffer, BufferSize);
330
331 gBS->FreePool (NewBuffer);
332
333 return Status;
334}
335
336
337/**
338 Converts Hex String to binary buffer in reversed byte order from R8_HexStringToBuf().
339
340 @param Buffer Pointer to buffer that receives the data.
341 @param BufferSize Length in bytes of the buffer to hold converted
342 data. If routine return with EFI_SUCCESS,
343 containing length of converted data. If routine
344 return with EFI_BUFFER_TOO_SMALL, containg length
345 of buffer desired.
346 @param Str String to be converted from.
347
348 @retval EFI_SUCCESS The function completed successfully.
349
350**/
351EFI_STATUS
352EFIAPI
353HexStringToBuffer (
354 IN OUT UINT8 *Buffer,
355 IN OUT UINTN *BufferSize,
356 IN CHAR16 *Str
357 )
358{
359 EFI_STATUS Status;
360 UINTN ConvertedStrLen;
361
362 ConvertedStrLen = 0;
363 Status = R8_HexStringToBuf (Buffer, BufferSize, Str, &ConvertedStrLen);
364 if (!EFI_ERROR (Status)) {
365 SwapBuffer (Buffer, ConvertedStrLen);
366 }
367
368 return Status;
369}
370
371
372/**
373 Construct <ConfigHdr> using routing information GUID/NAME/PATH.
374
375 @param ConfigHdr Pointer to the ConfigHdr string.
376 @param StrBufferLen On input: Length in bytes of buffer to hold the
377 ConfigHdr string. Includes tailing '\0' character.
378 On output: If return EFI_SUCCESS, containing
379 length of ConfigHdr string buffer. If return
380 EFI_BUFFER_TOO_SMALL, containg length of string
381 buffer desired.
382 @param Guid Routing information: GUID.
383 @param Name Routing information: NAME.
384 @param DriverHandle Driver handle which contains the routing
385 information: PATH.
386
387 @retval EFI_SUCCESS Routine success.
388 @retval EFI_BUFFER_TOO_SMALL The ConfigHdr string buffer is too small.
389
390**/
391EFI_STATUS
392EFIAPI
393ConstructConfigHdr (
394 IN OUT CHAR16 *ConfigHdr,
395 IN OUT UINTN *StrBufferLen,
396 IN EFI_GUID *Guid,
397 IN CHAR16 *Name, OPTIONAL
398 IN EFI_HANDLE *DriverHandle
399 )
400{
401 EFI_STATUS Status;
402 UINTN NameStrLen;
403 UINTN DevicePathSize;
404 UINTN BufferSize;
405 CHAR16 *StrPtr;
406 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
407
408 if (Name == NULL) {
409 //
410 // There will be no "NAME" in <ConfigHdr> for Name/Value storage
411 //
412 NameStrLen = 0;
413 } else {
414 //
415 // For buffer storage
416 //
417 NameStrLen = StrLen (Name);
418 }
419
420 //
421 // Retrieve DevicePath Protocol associated with this HiiPackageList
422 //
423 Status = gBS->HandleProtocol (
424 DriverHandle,
425 &gEfiDevicePathProtocolGuid,
426 (VOID **) &DevicePath
427 );
428 if (EFI_ERROR (Status)) {
429 return Status;
430 }
431
432 DevicePathSize = GetDevicePathSize (DevicePath);
433
434 //
435 // GUID=<HexCh>32&NAME=<Alpha>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL>
436 // | 5 | 32 | 6 | NameStrLen | 6 | DevicePathStrLen |
437 //
438 BufferSize = (5 + 32 + 6 + NameStrLen + 6 + DevicePathSize * 2 + 1) * sizeof (CHAR16);
439 if (*StrBufferLen < BufferSize) {
440 *StrBufferLen = BufferSize;
441 return EFI_BUFFER_TOO_SMALL;
442 }
443
444 *StrBufferLen = BufferSize;
445
446 StrPtr = ConfigHdr;
447
448 StrCpy (StrPtr, L"GUID=");
449 StrPtr += 5;
450 BufferToHexString (StrPtr, (UINT8 *) Guid, sizeof (EFI_GUID));
451 StrPtr += 32;
452
453 StrCpy (StrPtr, L"&NAME=");
454 StrPtr += 6;
455 if (Name != NULL) {
456 StrCpy (StrPtr, Name);
457 StrPtr += NameStrLen;
458 }
459
460 StrCpy (StrPtr, L"&PATH=");
461 StrPtr += 6;
462 BufferToHexString (StrPtr, (UINT8 *) DevicePath, DevicePathSize);
463
464 return EFI_SUCCESS;
465}
466
467
468/**
469 Search BlockName "&OFFSET=Offset&WIDTH=Width" in a string.
470
471 @param String The string to be searched in.
472 @param Offset Offset in BlockName.
473 @param Width Width in BlockName.
474
475 @retval TRUE Block name found.
476 @retval FALSE Block name not found.
477
478**/
479BOOLEAN
480FindBlockName (
481 IN OUT CHAR16 *String,
482 UINTN Offset,
483 UINTN Width
484 )
485{
486 EFI_STATUS Status;
487 UINTN Data;
488 UINTN BufferSize;
489 UINTN ConvertedStrLen;
490
491 while ((String = StrStr (String, L"&OFFSET=")) != NULL) {
492 //
493 // Skip '&OFFSET='
494 //
495 String = String + 8;
496
497 Data = 0;
498 BufferSize = sizeof (UINTN);
499 Status = R8_HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);
500 if (EFI_ERROR (Status)) {
501 return FALSE;
502 }
503 String = String + ConvertedStrLen;
504
505 if (Data != Offset) {
506 continue;
507 }
508
509 if (StrnCmp (String, L"&WIDTH=", 7) != 0) {
510 return FALSE;
511 }
512 String = String + 7;
513
514 Data = 0;
515 BufferSize = sizeof (UINTN);
516 Status = R8_HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);
517 if (EFI_ERROR (Status)) {
518 return FALSE;
519 }
520 if (Data == Width) {
521 return TRUE;
522 }
523
524 String = String + ConvertedStrLen;
525 }
526
527 return FALSE;
528}
529
530
531/**
532 This routine is invoked by ConfigAccess.Callback() to retrived uncommitted data from Form Browser.
533
534 @param VariableGuid An optional field to indicate the target variable
535 GUID name to use.
536 @param VariableName An optional field to indicate the target
537 human-readable variable name.
538 @param BufferSize On input: Length in bytes of buffer to hold
539 retrived data. On output: If return
540 EFI_BUFFER_TOO_SMALL, containg length of buffer
541 desired.
542 @param Buffer Buffer to hold retrived data.
543
544 @retval EFI_SUCCESS Routine success.
545 @retval EFI_BUFFER_TOO_SMALL The intput buffer is too small.
546
547**/
548EFI_STATUS
549EFIAPI
550GetBrowserData (
551 EFI_GUID *VariableGuid, OPTIONAL
552 CHAR16 *VariableName, OPTIONAL
553 UINTN *BufferSize,
554 UINT8 *Buffer
555 )
556{
557 EFI_STATUS Status;
558 CHAR16 *ConfigHdr;
559 CHAR16 *ConfigResp;
560 CHAR16 *StringPtr;
561 UINTN HeaderLen;
562 UINTN BufferLen;
563 CHAR16 *Progress;
564 EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
565 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
566
567 //
568 // Locate protocols for use
569 //
570 Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
571 if (EFI_ERROR (Status)) {
572 return Status;
573 }
574
575 Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
576 if (EFI_ERROR (Status)) {
577 return Status;
578 }
579
580 //
581 // Retrive formset storage data from Form Browser
582 //
583 ConfigHdr = mFakeConfigHdr;
584 HeaderLen = StrLen (ConfigHdr);
585
586 BufferLen = 0x4000;
587 ConfigResp = AllocateZeroPool (BufferLen + HeaderLen);
588
589 StringPtr = ConfigResp + HeaderLen;
590 *StringPtr = L'&';
591 StringPtr++;
592
593 Status = FormBrowser2->BrowserCallback (
594 FormBrowser2,
595 &BufferLen,
596 StringPtr,
597 TRUE,
598 VariableGuid,
599 VariableName
600 );
601 if (Status == EFI_BUFFER_TOO_SMALL) {
602 gBS->FreePool (ConfigResp);
603 ConfigResp = AllocateZeroPool (BufferLen + HeaderLen);
604
605 StringPtr = ConfigResp + HeaderLen;
606 *StringPtr = L'&';
607 StringPtr++;
608
609 Status = FormBrowser2->BrowserCallback (
610 FormBrowser2,
611 &BufferLen,
612 StringPtr,
613 TRUE,
614 VariableGuid,
615 VariableName
616 );
617 }
618 if (EFI_ERROR (Status)) {
619 gBS->FreePool (ConfigResp);
620 return Status;
621 }
622 CopyMem (ConfigResp, ConfigHdr, HeaderLen * sizeof (UINT16));
623
624 //
625 // Convert <ConfigResp> to buffer data
626 //
627 Status = HiiConfigRouting->ConfigToBlock (
628 HiiConfigRouting,
629 ConfigResp,
630 Buffer,
631 BufferSize,
632 &Progress
633 );
634 gBS->FreePool (ConfigResp);
635
636 return Status;
637}
638
639
640/**
641 This routine is invoked by ConfigAccess.Callback() to update uncommitted data of Form Browser.
642
643 @param VariableGuid An optional field to indicate the target variable
644 GUID name to use.
645 @param VariableName An optional field to indicate the target
646 human-readable variable name.
647 @param BufferSize Length in bytes of buffer to hold retrived data.
648 @param Buffer Buffer to hold retrived data.
649 @param RequestElement An optional field to specify which part of the
650 buffer data will be send back to Browser. If NULL,
651 the whole buffer of data will be committed to
652 Browser. <RequestElement> ::=
653 &OFFSET=<Number>&WIDTH=<Number>*
654
655 @retval EFI_SUCCESS Routine success.
656 @retval Other Updating Browser uncommitted data failed.
657
658**/
659EFI_STATUS
660EFIAPI
661SetBrowserData (
662 EFI_GUID *VariableGuid, OPTIONAL
663 CHAR16 *VariableName, OPTIONAL
664 UINTN BufferSize,
665 UINT8 *Buffer,
666 CHAR16 *RequestElement OPTIONAL
667 )
668{
669 EFI_STATUS Status;
670 CHAR16 *ConfigHdr;
671 CHAR16 *ConfigResp;
672 CHAR16 *StringPtr;
673 UINTN HeaderLen;
674 UINTN BufferLen;
675 CHAR16 *Progress;
676 EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
677 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
678 CHAR16 BlockName[33];
679 CHAR16 *ConfigRequest;
680 CHAR16 *Request;
681
682 //
683 // Locate protocols for use
684 //
685 Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
686 if (EFI_ERROR (Status)) {
687 return Status;
688 }
689
690 Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
691 if (EFI_ERROR (Status)) {
692 return Status;
693 }
694
695 //
696 // Prepare <ConfigRequest>
697 //
698 ConfigHdr = mFakeConfigHdr;
699 HeaderLen = StrLen (ConfigHdr);
700
701 if (RequestElement == NULL) {
702 //
703 // RequestElement not specified, use "&OFFSET=0&WIDTH=<BufferSize>" as <BlockName>
704 //
705 BlockName[0] = L'\0';
706 StrCpy (BlockName, L"&OFFSET=0&WIDTH=");
707
708 //
709 // String lenghth of L"&OFFSET=0&WIDTH=" is 16
710 //
711 StringPtr = BlockName + 16;
712 BufferLen = sizeof (BlockName) - (16 * sizeof (CHAR16));
713 R8_BufToHexString (StringPtr, &BufferLen, (UINT8 *) &BufferSize, sizeof (UINTN));
714
715 Request = BlockName;
716 } else {
717 Request = RequestElement;
718 }
719
720 BufferLen = HeaderLen * sizeof (CHAR16) + StrSize (Request);
721 ConfigRequest = AllocateZeroPool (BufferLen);
722
723 CopyMem (ConfigRequest, ConfigHdr, HeaderLen * sizeof (CHAR16));
724 StringPtr = ConfigRequest + HeaderLen;
725 StrCpy (StringPtr, Request);
726
727 //
728 // Convert buffer to <ConfigResp>
729 //
730 Status = HiiConfigRouting->BlockToConfig (
731 HiiConfigRouting,
732 ConfigRequest,
733 Buffer,
734 BufferSize,
735 &ConfigResp,
736 &Progress
737 );
738 if (EFI_ERROR (Status)) {
739 gBS->FreePool (ConfigResp);
740 return Status;
741 }
742
743 //
744 // Skip <ConfigHdr> and '&'
745 //
746 StringPtr = ConfigResp + HeaderLen + 1;
747
748 //
749 // Change uncommitted data in Browser
750 //
751 Status = FormBrowser2->BrowserCallback (
752 FormBrowser2,
753 &BufferSize,
754 StringPtr,
755 FALSE,
756 NULL,
757 NULL
758 );
759 gBS->FreePool (ConfigResp);
760 return Status;
761}