]>
Commit | Line | Data |
---|---|---|
e52c5a9f | 1 | /** @file |
2 | ||
3 | Copyright (c) 2007, Intel Corporation | |
4 | All rights reserved. This program and the accompanying materials | |
5 | are licensed and made available under the terms and conditions of the BSD License | |
6 | which accompanies this distribution. The full text of the license may be found at | |
7 | http://opensource.org/licenses/bsd-license.php | |
8 | ||
9 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
10 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
11 | ||
12 | Module Name: | |
13 | ||
14 | UefiIfrForm.c | |
15 | ||
16 | Abstract: | |
17 | ||
18 | Common Library Routines to assist handle HII elements. | |
19 | ||
20 | ||
21 | **/ | |
22 | ||
23 | #include "UefiIfrLibraryInternal.h" | |
24 | ||
25 | // | |
26 | // Fake <ConfigHdr> | |
27 | // | |
28 | UINT16 mFakeConfigHdr[] = L"GUID=00000000000000000000000000000000&NAME=0000&PATH=0"; | |
29 | ||
168f4233 | 30 | #if 0 |
e52c5a9f | 31 | STATIC |
32 | EFI_STATUS | |
33 | GetPackageDataFromPackageList ( | |
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 | **/ | |
93 | EFI_STATUS | |
94 | EFIAPI | |
95 | IfrLibCreatePopUp ( | |
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 | **/ | |
283 | STATIC | |
284 | VOID | |
285 | SwapBuffer ( | |
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 | **/ | |
313 | EFI_STATUS | |
314 | EFIAPI | |
315 | BufferToHexString ( | |
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 | **/ | |
351 | EFI_STATUS | |
352 | EFIAPI | |
353 | HexStringToBuffer ( | |
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 | **/ | |
391 | EFI_STATUS | |
392 | EFIAPI | |
393 | ConstructConfigHdr ( | |
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 | **/ | |
479 | BOOLEAN | |
480 | FindBlockName ( | |
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 | **/ | |
548 | EFI_STATUS | |
549 | EFIAPI | |
550 | GetBrowserData ( | |
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 | **/ | |
659 | EFI_STATUS | |
660 | EFIAPI | |
661 | SetBrowserData ( | |
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 | } |