1 /** @file
2 This is an example of how a driver might export data to the HII protocol to be
3 later utilized by the Setup Protocol
4 
5 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 
11 #include "DriverSample.h"
12 
13 #define DISPLAY_ONLY_MY_ITEM  0x0002
14 
15 CHAR16     VariableName[] = L"MyIfrNVData";
16 CHAR16     MyEfiVar[] = L"MyEfiVar";
17 CHAR16     MyEfiBitVar[] = L"MyEfiBitVar";
18 CHAR16     MyEfiUnionVar[] = L"MyEfiUnionVar";
19 
20 EFI_HANDLE                      DriverHandle[2] = {NULL, NULL};
21 DRIVER_SAMPLE_PRIVATE_DATA      *mPrivateData = NULL;
22 EFI_EVENT                       mEvent;
23 
24 HII_VENDOR_DEVICE_PATH  mHiiVendorDevicePath0 = {
25   {
26     {
27       HARDWARE_DEVICE_PATH,
28       HW_VENDOR_DP,
29       {
30         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
31         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
32       }
33     },
34     DRIVER_SAMPLE_FORMSET_GUID
35   },
36   {
37     END_DEVICE_PATH_TYPE,
38     END_ENTIRE_DEVICE_PATH_SUBTYPE,
39     {
40       (UINT8) (END_DEVICE_PATH_LENGTH),
41       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
42     }
43   }
44 };
45 
46 HII_VENDOR_DEVICE_PATH  mHiiVendorDevicePath1 = {
47   {
48     {
49       HARDWARE_DEVICE_PATH,
50       HW_VENDOR_DP,
51       {
52         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
53         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
54       }
55     },
56     DRIVER_SAMPLE_INVENTORY_GUID
57   },
58   {
59     END_DEVICE_PATH_TYPE,
60     END_ENTIRE_DEVICE_PATH_SUBTYPE,
61     {
62       (UINT8) (END_DEVICE_PATH_LENGTH),
63       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
64     }
65   }
66 };
67 
68 /**
69   Set value of a data element in an Array by its Index.
70 
71   @param  Array                  The data array.
72   @param  Type                   Type of the data in this array.
73   @param  Index                  Zero based index for data in this array.
74   @param  Value                  The value to be set.
75 
76 **/
77 VOID
SetArrayData(IN VOID * Array,IN UINT8 Type,IN UINTN Index,IN UINT64 Value)78 SetArrayData (
79   IN VOID                     *Array,
80   IN UINT8                    Type,
81   IN UINTN                    Index,
82   IN UINT64                   Value
83   )
84 {
85 
86   ASSERT (Array != NULL);
87 
88   switch (Type) {
89   case EFI_IFR_TYPE_NUM_SIZE_8:
90     *(((UINT8 *) Array) + Index) = (UINT8) Value;
91     break;
92 
93   case EFI_IFR_TYPE_NUM_SIZE_16:
94     *(((UINT16 *) Array) + Index) = (UINT16) Value;
95     break;
96 
97   case EFI_IFR_TYPE_NUM_SIZE_32:
98     *(((UINT32 *) Array) + Index) = (UINT32) Value;
99     break;
100 
101   case EFI_IFR_TYPE_NUM_SIZE_64:
102     *(((UINT64 *) Array) + Index) = (UINT64) Value;
103     break;
104 
105   default:
106     break;
107   }
108 }
109 
110 /**
111   Notification function for keystrokes.
112 
113   @param[in] KeyData    The key that was pressed.
114 
115   @retval EFI_SUCCESS   The operation was successful.
116 **/
117 EFI_STATUS
118 EFIAPI
NotificationFunction(IN EFI_KEY_DATA * KeyData)119 NotificationFunction(
120   IN EFI_KEY_DATA *KeyData
121   )
122 {
123   gBS->SignalEvent (mEvent);
124 
125   return EFI_SUCCESS;
126 }
127 
128 /**
129   Function to start monitoring for CTRL-C using SimpleTextInputEx.
130 
131   @retval EFI_SUCCESS           The feature is enabled.
132   @retval EFI_OUT_OF_RESOURCES  There is not enough mnemory available.
133 **/
134 EFI_STATUS
135 EFIAPI
InternalStartMonitor(VOID)136 InternalStartMonitor(
137   VOID
138   )
139 {
140   EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;
141   EFI_KEY_DATA                      KeyData;
142   EFI_STATUS                        Status;
143   EFI_HANDLE                        *Handles;
144   UINTN                             HandleCount;
145   UINTN                             HandleIndex;
146   VOID                              *NotifyHandle;
147 
148   Status = gBS->LocateHandleBuffer (
149               ByProtocol,
150               &gEfiSimpleTextInputExProtocolGuid,
151               NULL,
152               &HandleCount,
153               &Handles
154               );
155   for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
156     Status = gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &SimpleEx);
157     ASSERT_EFI_ERROR (Status);
158 
159     KeyData.KeyState.KeyToggleState = 0;
160     KeyData.Key.ScanCode            = 0;
161     KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED;
162     KeyData.Key.UnicodeChar         = L'c';
163 
164     Status = SimpleEx->RegisterKeyNotify(
165       SimpleEx,
166       &KeyData,
167       NotificationFunction,
168       &NotifyHandle);
169     if (EFI_ERROR (Status)) {
170       break;
171     }
172 
173     KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;
174     Status = SimpleEx->RegisterKeyNotify(
175       SimpleEx,
176       &KeyData,
177       NotificationFunction,
178       &NotifyHandle);
179     if (EFI_ERROR (Status)) {
180       break;
181     }
182   }
183 
184   return EFI_SUCCESS;
185 }
186 
187 /**
188   Function to stop monitoring for CTRL-C using SimpleTextInputEx.
189 
190   @retval EFI_SUCCESS           The feature is enabled.
191   @retval EFI_OUT_OF_RESOURCES  There is not enough mnemory available.
192 **/
193 EFI_STATUS
194 EFIAPI
InternalStopMonitor(VOID)195 InternalStopMonitor(
196   VOID
197   )
198 {
199   EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;
200   EFI_STATUS                        Status;
201   EFI_HANDLE                        *Handles;
202   EFI_KEY_DATA                      KeyData;
203   UINTN                             HandleCount;
204   UINTN                             HandleIndex;
205   VOID                              *NotifyHandle;
206 
207   Status = gBS->LocateHandleBuffer (
208                 ByProtocol,
209                 &gEfiSimpleTextInputExProtocolGuid,
210                 NULL,
211                 &HandleCount,
212                 &Handles
213                 );
214   for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
215     Status = gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &SimpleEx);
216     ASSERT_EFI_ERROR (Status);
217 
218     KeyData.KeyState.KeyToggleState = 0;
219     KeyData.Key.ScanCode            = 0;
220     KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED;
221     KeyData.Key.UnicodeChar         = L'c';
222 
223     Status = SimpleEx->RegisterKeyNotify(
224       SimpleEx,
225       &KeyData,
226       NotificationFunction,
227       &NotifyHandle);
228     if (!EFI_ERROR (Status)) {
229       Status = SimpleEx->UnregisterKeyNotify (SimpleEx, NotifyHandle);
230     }
231 
232     KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;
233     Status = SimpleEx->RegisterKeyNotify(
234       SimpleEx,
235       &KeyData,
236       NotificationFunction,
237       &NotifyHandle);
238     if (!EFI_ERROR (Status)) {
239       Status = SimpleEx->UnregisterKeyNotify (SimpleEx, NotifyHandle);
240     }
241   }
242   return EFI_SUCCESS;
243 }
244 
245 /**
246  Update names of Name/Value storage to current language.
247 
248  @param PrivateData   Points to the driver private data.
249 
250  @retval EFI_SUCCESS   All names are successfully updated.
251  @retval EFI_NOT_FOUND Failed to get Name from HII database.
252 
253 **/
254 EFI_STATUS
LoadNameValueNames(IN DRIVER_SAMPLE_PRIVATE_DATA * PrivateData)255 LoadNameValueNames (
256   IN DRIVER_SAMPLE_PRIVATE_DATA      *PrivateData
257   )
258 {
259   UINTN      Index;
260 
261   //
262   // Get Name/Value name string of current language
263   //
264   for (Index = 0; Index < NAME_VALUE_NAME_NUMBER; Index++) {
265     PrivateData->NameValueName[Index] = HiiGetString (
266                                          PrivateData->HiiHandle[0],
267                                          PrivateData->NameStringId[Index],
268                                          NULL
269                                          );
270     if (PrivateData->NameValueName[Index] == NULL) {
271       return EFI_NOT_FOUND;
272     }
273   }
274 
275   return EFI_SUCCESS;
276 }
277 
278 
279 /**
280   Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
281   or WIDTH or VALUE.
282   <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
283 
284   This is a internal function.
285 
286   @param  StringPtr              String in <BlockConfig> format and points to the
287                                  first character of <Number>.
288   @param  Number                 The output value. Caller takes the responsibility
289                                  to free memory.
290   @param  Len                    Length of the <Number>, in characters.
291 
292   @retval EFI_OUT_OF_RESOURCES   Insufficient resources to store neccessary
293                                  structures.
294   @retval EFI_SUCCESS            Value of <Number> is outputted in Number
295                                  successfully.
296 
297 **/
298 EFI_STATUS
GetValueOfNumber(IN EFI_STRING StringPtr,OUT UINT8 ** Number,OUT UINTN * Len)299 GetValueOfNumber (
300   IN EFI_STRING                    StringPtr,
301   OUT UINT8                        **Number,
302   OUT UINTN                        *Len
303   )
304 {
305   EFI_STRING               TmpPtr;
306   UINTN                    Length;
307   EFI_STRING               Str;
308   UINT8                    *Buf;
309   EFI_STATUS               Status;
310   UINT8                    DigitUint8;
311   UINTN                    Index;
312   CHAR16                   TemStr[2];
313 
314   if (StringPtr == NULL || *StringPtr == L'\0' || Number == NULL || Len == NULL) {
315     return EFI_INVALID_PARAMETER;
316   }
317 
318   Buf = NULL;
319 
320   TmpPtr = StringPtr;
321   while (*StringPtr != L'\0' && *StringPtr != L'&') {
322     StringPtr++;
323   }
324   *Len   = StringPtr - TmpPtr;
325   Length = *Len + 1;
326 
327   Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
328   if (Str == NULL) {
329     Status = EFI_OUT_OF_RESOURCES;
330     goto Exit;
331   }
332   CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16));
333   *(Str + *Len) = L'\0';
334 
335   Length = (Length + 1) / 2;
336   Buf = (UINT8 *) AllocateZeroPool (Length);
337   if (Buf == NULL) {
338     Status = EFI_OUT_OF_RESOURCES;
339     goto Exit;
340   }
341 
342   Length = *Len;
343   ZeroMem (TemStr, sizeof (TemStr));
344   for (Index = 0; Index < Length; Index ++) {
345     TemStr[0] = Str[Length - Index - 1];
346     DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
347     if ((Index & 1) == 0) {
348       Buf [Index/2] = DigitUint8;
349     } else {
350       Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]);
351     }
352   }
353 
354   *Number = Buf;
355   Status  = EFI_SUCCESS;
356 
357 Exit:
358   if (Str != NULL) {
359     FreePool (Str);
360   }
361 
362   return Status;
363 }
364 
365 /**
366   Create altcfg string.
367 
368   @param  Result               The request result string.
369   @param  ConfigHdr            The request head info. <ConfigHdr> format.
370   @param  Offset               The offset of the parameter int he structure.
371   @param  Width                The width of the parameter.
372 
373 
374   @retval  The string with altcfg info append at the end.
375 **/
376 EFI_STRING
CreateAltCfgString(IN EFI_STRING Result,IN EFI_STRING ConfigHdr,IN UINTN Offset,IN UINTN Width)377 CreateAltCfgString (
378   IN     EFI_STRING     Result,
379   IN     EFI_STRING     ConfigHdr,
380   IN     UINTN          Offset,
381   IN     UINTN          Width
382   )
383 {
384   EFI_STRING StringPtr;
385   EFI_STRING TmpStr;
386   UINTN      NewLen;
387 
388   NewLen = StrLen (Result);
389   //
390   // String Len = ConfigResp + AltConfig + AltConfig + 1("\0")
391   //
392   NewLen = (NewLen + ((1 + StrLen (ConfigHdr) + 8 + 4) + (8 + 4 + 7 + 4 + 7 + 4)) * 2 + 1) * sizeof (CHAR16);
393   StringPtr = AllocateZeroPool (NewLen);
394   if (StringPtr == NULL) {
395     return NULL;
396   }
397 
398   TmpStr = StringPtr;
399   if (Result != NULL) {
400     StrCpyS (StringPtr, NewLen / sizeof (CHAR16), Result);
401     StringPtr += StrLen (Result);
402     FreePool (Result);
403   }
404 
405   UnicodeSPrint (
406   StringPtr,
407   (1 + StrLen (ConfigHdr) + 8 + 4 + 1) * sizeof (CHAR16),
408   L"&%s&ALTCFG=%04x",
409   ConfigHdr,
410   EFI_HII_DEFAULT_CLASS_STANDARD
411   );
412   StringPtr += StrLen (StringPtr);
413 
414   UnicodeSPrint (
415     StringPtr,
416     (8 + 4 + 7 + 4 + 7 + 4 + 1) * sizeof (CHAR16),
417     L"&OFFSET=%04x&WIDTH=%04x&VALUE=%04x",
418     Offset,
419     Width,
420     DEFAULT_CLASS_STANDARD_VALUE
421     );
422   StringPtr += StrLen (StringPtr);
423 
424   UnicodeSPrint (
425   StringPtr,
426   (1 + StrLen (ConfigHdr) + 8 + 4 + 1) * sizeof (CHAR16),
427   L"&%s&ALTCFG=%04x",
428   ConfigHdr,
429   EFI_HII_DEFAULT_CLASS_MANUFACTURING
430   );
431   StringPtr += StrLen (StringPtr);
432 
433   UnicodeSPrint (
434     StringPtr,
435     (8 + 4 + 7 + 4 + 7 + 4 + 1) * sizeof (CHAR16),
436     L"&OFFSET=%04x&WIDTH=%04x&VALUE=%04x",
437     Offset,
438     Width,
439     DEFAULT_CLASS_MANUFACTURING_VALUE
440     );
441   StringPtr += StrLen (StringPtr);
442 
443   return TmpStr;
444 }
445 
446 /**
447   Check whether need to add the altcfg string. if need to add, add the altcfg
448   string.
449 
450   @param  RequestResult              The request result string.
451   @param  ConfigRequestHdr           The request head info. <ConfigHdr> format.
452 
453 **/
454 VOID
AppendAltCfgString(IN OUT EFI_STRING * RequestResult,IN EFI_STRING ConfigRequestHdr)455 AppendAltCfgString (
456   IN OUT EFI_STRING                       *RequestResult,
457   IN     EFI_STRING                       ConfigRequestHdr
458   )
459 {
460   EFI_STRING                          StringPtr;
461   UINTN                               Length;
462   UINT8                               *TmpBuffer;
463   UINTN                               Offset;
464   UINTN                               Width;
465   UINTN                               BlockSize;
466   UINTN                               ValueOffset;
467   UINTN                               ValueWidth;
468   EFI_STATUS                          Status;
469 
470   TmpBuffer = NULL;
471   StringPtr = *RequestResult;
472   StringPtr = StrStr (StringPtr, L"OFFSET");
473   BlockSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
474   ValueOffset = OFFSET_OF (DRIVER_SAMPLE_CONFIGURATION, GetDefaultValueFromAccess);
475   ValueWidth  = sizeof (((DRIVER_SAMPLE_CONFIGURATION *)0)->GetDefaultValueFromAccess);
476 
477   if (StringPtr == NULL) {
478     return;
479   }
480 
481   while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
482     StringPtr += StrLen (L"OFFSET=");
483     //
484     // Get Offset
485     //
486     Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
487     if (EFI_ERROR (Status)) {
488       return;
489     }
490     Offset = 0;
491     CopyMem (
492      &Offset,
493      TmpBuffer,
494      (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
495      );
496     FreePool (TmpBuffer);
497 
498     StringPtr += Length;
499     if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
500       return;
501     }
502     StringPtr += StrLen (L"&WIDTH=");
503 
504     //
505     // Get Width
506     //
507     Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
508     if (EFI_ERROR (Status)) {
509       return;
510     }
511     Width = 0;
512     CopyMem (
513      &Width,
514      TmpBuffer,
515      (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
516      );
517     FreePool (TmpBuffer);
518 
519     StringPtr += Length;
520     if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
521       return;
522     }
523     StringPtr += StrLen (L"&VALUE=");
524 
525     //
526     // Get Value
527     //
528     Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
529     if (EFI_ERROR (Status)) {
530       return;
531     }
532     StringPtr += Length;
533 
534     //
535     // Skip the character "&" before "OFFSET".
536     //
537     StringPtr ++;
538 
539     //
540     // Calculate Value and convert it to hex string.
541     //
542     if (Offset + Width > BlockSize) {
543       return;
544     }
545 
546     if (Offset <= ValueOffset && Offset + Width >= ValueOffset + ValueWidth) {
547       *RequestResult = CreateAltCfgString(*RequestResult, ConfigRequestHdr, ValueOffset, ValueWidth);
548       return;
549     }
550   }
551 }
552 
553 /**
554   This function allows a caller to extract the current configuration for one
555   or more named elements from the target driver.
556 
557   @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
558   @param  Request                A null-terminated Unicode string in
559                                  <ConfigRequest> format.
560   @param  Progress               On return, points to a character in the Request
561                                  string. Points to the string's null terminator if
562                                  request was successful. Points to the most recent
563                                  '&' before the first failing name/value pair (or
564                                  the beginning of the string if the failure is in
565                                  the first name/value pair) if the request was not
566                                  successful.
567   @param  Results                A null-terminated Unicode string in
568                                  <ConfigAltResp> format which has all values filled
569                                  in for the names in the Request string. String to
570                                  be allocated by the called function.
571 
572   @retval EFI_SUCCESS            The Results is filled with the requested values.
573   @retval EFI_OUT_OF_RESOURCES   Not enough memory to store the results.
574   @retval EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.
575   @retval EFI_NOT_FOUND          Routing data doesn't match any storage in this
576                                  driver.
577 
578 **/
579 EFI_STATUS
580 EFIAPI
ExtractConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)581 ExtractConfig (
582   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
583   IN  CONST EFI_STRING                       Request,
584   OUT EFI_STRING                             *Progress,
585   OUT EFI_STRING                             *Results
586   )
587 {
588   EFI_STATUS                       Status;
589   UINTN                            BufferSize;
590   DRIVER_SAMPLE_PRIVATE_DATA       *PrivateData;
591   EFI_HII_CONFIG_ROUTING_PROTOCOL  *HiiConfigRouting;
592   EFI_STRING                       ConfigRequest;
593   EFI_STRING                       ConfigRequestHdr;
594   UINTN                            Size;
595   EFI_STRING                       Value;
596   UINTN                            ValueStrLen;
597   CHAR16                           BackupChar;
598   CHAR16                           *StrPointer;
599   BOOLEAN                          AllocatedRequest;
600 
601   if (Progress == NULL || Results == NULL) {
602     return EFI_INVALID_PARAMETER;
603   }
604   //
605   // Initialize the local variables.
606   //
607   ConfigRequestHdr  = NULL;
608   ConfigRequest     = NULL;
609   Size              = 0;
610   *Progress         = Request;
611   AllocatedRequest  = FALSE;
612 
613   PrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This);
614   HiiConfigRouting = PrivateData->HiiConfigRouting;
615 
616   //
617   // Get Buffer Storage data from EFI variable.
618   // Try to get the current setting from variable.
619   //
620   BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
621   Status = gRT->GetVariable (
622             VariableName,
623             &gDriverSampleFormSetGuid,
624             NULL,
625             &BufferSize,
626             &PrivateData->Configuration
627             );
628   if (EFI_ERROR (Status)) {
629     return EFI_NOT_FOUND;
630   }
631 
632   if (Request == NULL) {
633     //
634     // Request is set to NULL, construct full request string.
635     //
636 
637     //
638     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
639     // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
640     //
641     ConfigRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, VariableName, PrivateData->DriverHandle[0]);
642     Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
643     ConfigRequest = AllocateZeroPool (Size);
644     ASSERT (ConfigRequest != NULL);
645     AllocatedRequest = TRUE;
646     UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
647     FreePool (ConfigRequestHdr);
648     ConfigRequestHdr = NULL;
649   } else {
650     //
651     // Check routing data in <ConfigHdr>.
652     // Note: if only one Storage is used, then this checking could be skipped.
653     //
654     if (!HiiIsConfigHdrMatch (Request, &gDriverSampleFormSetGuid, NULL)) {
655       return EFI_NOT_FOUND;
656     }
657     //
658     // Check whether request for EFI Varstore. EFI varstore get data
659     // through hii database, not support in this path.
660     //
661     if (HiiIsConfigHdrMatch(Request, &gDriverSampleFormSetGuid, MyEfiVar)) {
662       return EFI_UNSUPPORTED;
663     }
664     if (HiiIsConfigHdrMatch(Request, &gDriverSampleFormSetGuid, MyEfiBitVar)) {
665       return EFI_UNSUPPORTED;
666     }
667     if (HiiIsConfigHdrMatch(Request, &gDriverSampleFormSetGuid, MyEfiUnionVar)) {
668       return EFI_UNSUPPORTED;
669     }
670 
671     //
672     // Set Request to the unified request string.
673     //
674     ConfigRequest = Request;
675     //
676     // Check whether Request includes Request Element.
677     //
678     if (StrStr (Request, L"OFFSET") == NULL) {
679       //
680       // Check Request Element does exist in Reques String
681       //
682       StrPointer = StrStr (Request, L"PATH");
683       if (StrPointer == NULL) {
684         return EFI_INVALID_PARAMETER;
685       }
686       if (StrStr (StrPointer, L"&") == NULL) {
687         Size = (StrLen (Request) + 32 + 1) * sizeof (CHAR16);
688         ConfigRequest    = AllocateZeroPool (Size);
689         ASSERT (ConfigRequest != NULL);
690         AllocatedRequest = TRUE;
691         UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", Request, (UINT64)BufferSize);
692       }
693     }
694   }
695 
696   //
697   // Check if requesting Name/Value storage
698   //
699   if (StrStr (ConfigRequest, L"OFFSET") == NULL) {
700     //
701     // Update Name/Value storage Names
702     //
703     Status = LoadNameValueNames (PrivateData);
704     if (EFI_ERROR (Status)) {
705       return Status;
706     }
707 
708     //
709     // Allocate memory for <ConfigResp>, e.g. Name0=0x11, Name1=0x1234, Name2="ABCD"
710     // <Request>   ::=<ConfigHdr>&Name0&Name1&Name2
711     // <ConfigResp>::=<ConfigHdr>&Name0=11&Name1=1234&Name2=0041004200430044
712     //
713     BufferSize = (StrLen (ConfigRequest) +
714       1 + sizeof (PrivateData->Configuration.NameValueVar0) * 2 +
715       1 + sizeof (PrivateData->Configuration.NameValueVar1) * 2 +
716       1 + sizeof (PrivateData->Configuration.NameValueVar2) * 2 + 1) * sizeof (CHAR16);
717     *Results = AllocateZeroPool (BufferSize);
718     ASSERT (*Results != NULL);
719     StrCpyS (*Results, BufferSize / sizeof (CHAR16), ConfigRequest);
720     Value = *Results;
721 
722     //
723     // Append value of NameValueVar0, type is UINT8
724     //
725     if ((Value = StrStr (*Results, PrivateData->NameValueName[0])) != NULL) {
726       Value += StrLen (PrivateData->NameValueName[0]);
727       ValueStrLen = ((sizeof (PrivateData->Configuration.NameValueVar0) * 2) + 1);
728       CopyMem (Value + ValueStrLen, Value, StrSize (Value));
729 
730       BackupChar = Value[ValueStrLen];
731       *Value++   = L'=';
732       UnicodeValueToStringS (
733         Value,
734         BufferSize - ((UINTN)Value - (UINTN)*Results),
735         PREFIX_ZERO | RADIX_HEX,
736         PrivateData->Configuration.NameValueVar0,
737         sizeof (PrivateData->Configuration.NameValueVar0) * 2
738         );
739       Value += StrnLenS (Value, (BufferSize - ((UINTN)Value - (UINTN)*Results)) / sizeof (CHAR16));
740       *Value = BackupChar;
741     }
742 
743     //
744     // Append value of NameValueVar1, type is UINT16
745     //
746     if ((Value = StrStr (*Results, PrivateData->NameValueName[1])) != NULL) {
747       Value += StrLen (PrivateData->NameValueName[1]);
748       ValueStrLen = ((sizeof (PrivateData->Configuration.NameValueVar1) * 2) + 1);
749       CopyMem (Value + ValueStrLen, Value, StrSize (Value));
750 
751       BackupChar = Value[ValueStrLen];
752       *Value++   = L'=';
753       UnicodeValueToStringS (
754         Value,
755         BufferSize - ((UINTN)Value - (UINTN)*Results),
756         PREFIX_ZERO | RADIX_HEX,
757         PrivateData->Configuration.NameValueVar1,
758         sizeof (PrivateData->Configuration.NameValueVar1) * 2
759         );
760       Value += StrnLenS (Value, (BufferSize - ((UINTN)Value - (UINTN)*Results)) / sizeof (CHAR16));
761       *Value = BackupChar;
762     }
763 
764     //
765     // Append value of NameValueVar2, type is CHAR16 *
766     //
767     if ((Value = StrStr (*Results, PrivateData->NameValueName[2])) != NULL) {
768       Value += StrLen (PrivateData->NameValueName[2]);
769       ValueStrLen = StrLen (PrivateData->Configuration.NameValueVar2) * 4 + 1;
770       CopyMem (Value + ValueStrLen, Value, StrSize (Value));
771 
772       *Value++ = L'=';
773       //
774       // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
775       //
776       StrPointer = (CHAR16 *) PrivateData->Configuration.NameValueVar2;
777       for (; *StrPointer != L'\0'; StrPointer++) {
778         UnicodeValueToStringS (
779           Value,
780           BufferSize - ((UINTN)Value - (UINTN)*Results),
781           PREFIX_ZERO | RADIX_HEX,
782           *StrPointer,
783           4
784           );
785         Value += StrnLenS (Value, (BufferSize - ((UINTN)Value - (UINTN)*Results)) / sizeof (CHAR16));
786       }
787     }
788 
789     Status = EFI_SUCCESS;
790   } else {
791     //
792     // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
793     //
794     Status = HiiConfigRouting->BlockToConfig (
795                                   HiiConfigRouting,
796                                   ConfigRequest,
797                                   (UINT8 *) &PrivateData->Configuration,
798                                   BufferSize,
799                                   Results,
800                                   Progress
801                                   );
802     if (!EFI_ERROR (Status)) {
803       ConfigRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, VariableName, PrivateData->DriverHandle[0]);
804       AppendAltCfgString(Results, ConfigRequestHdr);
805     }
806   }
807 
808   //
809   // Free the allocated config request string.
810   //
811   if (AllocatedRequest) {
812     FreePool (ConfigRequest);
813   }
814 
815   if (ConfigRequestHdr != NULL) {
816     FreePool (ConfigRequestHdr);
817   }
818   //
819   // Set Progress string to the original request string.
820   //
821   if (Request == NULL) {
822     *Progress = NULL;
823   } else if (StrStr (Request, L"OFFSET") == NULL) {
824     *Progress = Request + StrLen (Request);
825   }
826 
827   return Status;
828 }
829 
830 
831 /**
832   This function processes the results of changes in configuration.
833 
834   @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
835   @param  Configuration          A null-terminated Unicode string in <ConfigResp>
836                                  format.
837   @param  Progress               A pointer to a string filled in with the offset of
838                                  the most recent '&' before the first failing
839                                  name/value pair (or the beginning of the string if
840                                  the failure is in the first name/value pair) or
841                                  the terminating NULL if all was successful.
842 
843   @retval EFI_SUCCESS            The Results is processed successfully.
844   @retval EFI_INVALID_PARAMETER  Configuration is NULL.
845   @retval EFI_NOT_FOUND          Routing data doesn't match any storage in this
846                                  driver.
847 
848 **/
849 EFI_STATUS
850 EFIAPI
RouteConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)851 RouteConfig (
852   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
853   IN  CONST EFI_STRING                       Configuration,
854   OUT EFI_STRING                             *Progress
855   )
856 {
857   EFI_STATUS                       Status;
858   UINTN                            BufferSize;
859   DRIVER_SAMPLE_PRIVATE_DATA       *PrivateData;
860   EFI_HII_CONFIG_ROUTING_PROTOCOL  *HiiConfigRouting;
861   CHAR16                           *Value;
862   CHAR16                           *StrPtr;
863   CHAR16                           TemStr[5];
864   UINT8                            *DataBuffer;
865   UINT8                            DigitUint8;
866   UINTN                            Index;
867   CHAR16                           *StrBuffer;
868 
869   if (Configuration == NULL || Progress == NULL) {
870     return EFI_INVALID_PARAMETER;
871   }
872 
873   PrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This);
874   HiiConfigRouting = PrivateData->HiiConfigRouting;
875   *Progress = Configuration;
876 
877   //
878   // Check routing data in <ConfigHdr>.
879   // Note: if only one Storage is used, then this checking could be skipped.
880   //
881   if (!HiiIsConfigHdrMatch (Configuration, &gDriverSampleFormSetGuid, NULL)) {
882     return EFI_NOT_FOUND;
883   }
884 
885   //
886   // Check whether request for EFI Varstore. EFI varstore get data
887   // through hii database, not support in this path.
888   //
889   if (HiiIsConfigHdrMatch(Configuration, &gDriverSampleFormSetGuid, MyEfiVar)) {
890     return EFI_UNSUPPORTED;
891   }
892   if (HiiIsConfigHdrMatch(Configuration, &gDriverSampleFormSetGuid, MyEfiBitVar)) {
893     return EFI_UNSUPPORTED;
894   }
895   if (HiiIsConfigHdrMatch(Configuration, &gDriverSampleFormSetGuid, MyEfiUnionVar)) {
896     return EFI_UNSUPPORTED;
897   }
898 
899   //
900   // Get Buffer Storage data from EFI variable
901   //
902   BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
903   Status = gRT->GetVariable (
904             VariableName,
905             &gDriverSampleFormSetGuid,
906             NULL,
907             &BufferSize,
908             &PrivateData->Configuration
909             );
910   if (EFI_ERROR (Status)) {
911     return Status;
912   }
913 
914   //
915   // Check if configuring Name/Value storage
916   //
917   if (StrStr (Configuration, L"OFFSET") == NULL) {
918     //
919     // Update Name/Value storage Names
920     //
921     Status = LoadNameValueNames (PrivateData);
922     if (EFI_ERROR (Status)) {
923       return Status;
924     }
925 
926     //
927     // Convert value for NameValueVar0
928     //
929     if ((Value = StrStr (Configuration, PrivateData->NameValueName[0])) != NULL) {
930       //
931       // Skip "Name="
932       //
933       Value += StrLen (PrivateData->NameValueName[0]);
934       Value++;
935       //
936       // Get Value String
937       //
938       StrPtr = StrStr (Value, L"&");
939       if (StrPtr == NULL) {
940         StrPtr = Value + StrLen (Value);
941       }
942       //
943       // Convert Value to Buffer data
944       //
945       DataBuffer = (UINT8 *) &PrivateData->Configuration.NameValueVar0;
946       ZeroMem (TemStr, sizeof (TemStr));
947       for (Index = 0, StrPtr --; StrPtr >= Value; StrPtr --, Index ++) {
948         TemStr[0] = *StrPtr;
949         DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
950         if ((Index & 1) == 0) {
951           DataBuffer [Index/2] = DigitUint8;
952         } else {
953           DataBuffer [Index/2] = (UINT8) ((UINT8) (DigitUint8 << 4) + DataBuffer [Index/2]);
954         }
955       }
956     }
957 
958     //
959     // Convert value for NameValueVar1
960     //
961     if ((Value = StrStr (Configuration, PrivateData->NameValueName[1])) != NULL) {
962       //
963       // Skip "Name="
964       //
965       Value += StrLen (PrivateData->NameValueName[1]);
966       Value++;
967       //
968       // Get Value String
969       //
970       StrPtr = StrStr (Value, L"&");
971       if (StrPtr == NULL) {
972         StrPtr = Value + StrLen (Value);
973       }
974       //
975       // Convert Value to Buffer data
976       //
977       DataBuffer = (UINT8 *) &PrivateData->Configuration.NameValueVar1;
978       ZeroMem (TemStr, sizeof (TemStr));
979       for (Index = 0, StrPtr --; StrPtr >= Value; StrPtr --, Index ++) {
980         TemStr[0] = *StrPtr;
981         DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
982         if ((Index & 1) == 0) {
983           DataBuffer [Index/2] = DigitUint8;
984         } else {
985           DataBuffer [Index/2] = (UINT8) ((UINT8) (DigitUint8 << 4) + DataBuffer [Index/2]);
986         }
987       }
988     }
989 
990     //
991     // Convert value for NameValueVar2
992     //
993     if ((Value = StrStr (Configuration, PrivateData->NameValueName[2])) != NULL) {
994       //
995       // Skip "Name="
996       //
997       Value += StrLen (PrivateData->NameValueName[2]);
998       Value++;
999       //
1000       // Get Value String
1001       //
1002       StrPtr = StrStr (Value, L"&");
1003       if (StrPtr == NULL) {
1004         StrPtr = Value + StrLen (Value);
1005       }
1006       //
1007       // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
1008       //
1009       StrBuffer = (CHAR16 *) PrivateData->Configuration.NameValueVar2;
1010       ZeroMem (TemStr, sizeof (TemStr));
1011       while (Value < StrPtr) {
1012         StrnCpyS (TemStr, sizeof (TemStr) / sizeof (CHAR16), Value, 4);
1013         *(StrBuffer++) = (CHAR16) StrHexToUint64 (TemStr);
1014         Value += 4;
1015       }
1016       *StrBuffer = L'\0';
1017     }
1018 
1019     //
1020     // Store Buffer Storage back to EFI variable
1021     //
1022     Status = gRT->SetVariable(
1023       VariableName,
1024       &gDriverSampleFormSetGuid,
1025       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
1026       sizeof (DRIVER_SAMPLE_CONFIGURATION),
1027       &PrivateData->Configuration
1028       );
1029 
1030     return Status;
1031   }
1032 
1033   //
1034   // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
1035   //
1036   BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
1037   Status = HiiConfigRouting->ConfigToBlock (
1038                                HiiConfigRouting,
1039                                Configuration,
1040                                (UINT8 *) &PrivateData->Configuration,
1041                                &BufferSize,
1042                                Progress
1043                                );
1044   if (EFI_ERROR (Status)) {
1045     return Status;
1046   }
1047 
1048   //
1049   // Store Buffer Storage back to EFI variable
1050   //
1051   Status = gRT->SetVariable(
1052                   VariableName,
1053                   &gDriverSampleFormSetGuid,
1054                   EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
1055                   sizeof (DRIVER_SAMPLE_CONFIGURATION),
1056                   &PrivateData->Configuration
1057                   );
1058 
1059   return Status;
1060 }
1061 
1062 
1063 /**
1064   This function processes the results of changes in configuration.
1065 
1066   @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
1067   @param  Action                 Specifies the type of action taken by the browser.
1068   @param  QuestionId             A unique value which is sent to the original
1069                                  exporting driver so that it can identify the type
1070                                  of data to expect.
1071   @param  Type                   The type of value for the question.
1072   @param  Value                  A pointer to the data being sent to the original
1073                                  exporting driver.
1074   @param  ActionRequest          On return, points to the action requested by the
1075                                  callback function.
1076 
1077   @retval EFI_SUCCESS            The callback successfully handled the action.
1078   @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the
1079                                  variable and its data.
1080   @retval EFI_DEVICE_ERROR       The variable could not be saved.
1081   @retval EFI_UNSUPPORTED        The specified Action is not supported by the
1082                                  callback.
1083 
1084 **/
1085 EFI_STATUS
1086 EFIAPI
DriverCallback(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN EFI_BROWSER_ACTION Action,IN EFI_QUESTION_ID QuestionId,IN UINT8 Type,IN EFI_IFR_TYPE_VALUE * Value,OUT EFI_BROWSER_ACTION_REQUEST * ActionRequest)1087 DriverCallback (
1088   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
1089   IN  EFI_BROWSER_ACTION                     Action,
1090   IN  EFI_QUESTION_ID                        QuestionId,
1091   IN  UINT8                                  Type,
1092   IN  EFI_IFR_TYPE_VALUE                     *Value,
1093   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
1094   )
1095 {
1096   DRIVER_SAMPLE_PRIVATE_DATA      *PrivateData;
1097   EFI_STATUS                      Status;
1098   VOID                            *StartOpCodeHandle;
1099   VOID                            *OptionsOpCodeHandle;
1100   EFI_IFR_GUID_LABEL              *StartLabel;
1101   VOID                            *EndOpCodeHandle;
1102   EFI_IFR_GUID_LABEL              *EndLabel;
1103   EFI_INPUT_KEY                   Key;
1104   DRIVER_SAMPLE_CONFIGURATION     *Configuration;
1105   MY_EFI_VARSTORE_DATA            *EfiData;
1106   EFI_FORM_ID                     FormId;
1107   EFI_STRING                      Progress;
1108   EFI_STRING                      Results;
1109   UINT32                          ProgressErr;
1110   CHAR16                          *TmpStr;
1111   UINTN                           Index;
1112   UINT64                          BufferValue;
1113   EFI_HII_POPUP_SELECTION         UserSelection;
1114 
1115   UserSelection = 0xFF;
1116 
1117   if (((Value == NULL) && (Action != EFI_BROWSER_ACTION_FORM_OPEN) && (Action != EFI_BROWSER_ACTION_FORM_CLOSE))||
1118     (ActionRequest == NULL)) {
1119     return EFI_INVALID_PARAMETER;
1120   }
1121 
1122 
1123   FormId = 0;
1124   ProgressErr = 0;
1125   Status = EFI_SUCCESS;
1126   BufferValue = 3;
1127   PrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This);
1128 
1129   switch (Action) {
1130   case EFI_BROWSER_ACTION_FORM_OPEN:
1131     {
1132       if (QuestionId == 0x1234) {
1133         //
1134         // Sample CallBack for UEFI FORM_OPEN action:
1135         //   Add Save action into Form 3 when Form 1 is opened.
1136         //   This will be done only in FORM_OPEN CallBack of question with ID 0x1234 from Form 1.
1137         //
1138         PrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This);
1139 
1140         //
1141         // Initialize the container for dynamic opcodes
1142         //
1143         StartOpCodeHandle = HiiAllocateOpCodeHandle ();
1144         ASSERT (StartOpCodeHandle != NULL);
1145 
1146         //
1147         // Create Hii Extend Label OpCode as the start opcode
1148         //
1149         StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1150         StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1151         StartLabel->Number       = LABEL_UPDATE2;
1152 
1153         HiiCreateActionOpCode (
1154           StartOpCodeHandle,                // Container for dynamic created opcodes
1155           0x1238,                           // Question ID
1156           STRING_TOKEN(STR_SAVE_TEXT),      // Prompt text
1157           STRING_TOKEN(STR_SAVE_TEXT),      // Help text
1158           EFI_IFR_FLAG_CALLBACK,            // Question flag
1159           0                                 // Action String ID
1160         );
1161 
1162         HiiUpdateForm (
1163           PrivateData->HiiHandle[0],  // HII handle
1164           &gDriverSampleFormSetGuid,  // Formset GUID
1165           0x3,                        // Form ID
1166           StartOpCodeHandle,          // Label for where to insert opcodes
1167           NULL                        // Insert data
1168           );
1169 
1170         HiiFreeOpCodeHandle (StartOpCodeHandle);
1171       }
1172 
1173       if (QuestionId == 0x1247) {
1174         Status = InternalStartMonitor ();
1175         ASSERT_EFI_ERROR (Status);
1176       }
1177     }
1178     break;
1179 
1180   case EFI_BROWSER_ACTION_FORM_CLOSE:
1181     {
1182       if (QuestionId == 0x5678) {
1183         //
1184         // Sample CallBack for UEFI FORM_CLOSE action:
1185         //   Show up a pop-up to specify Form 3 will be closed when exit Form 3.
1186         //
1187         do {
1188           CreatePopUp (
1189             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1190             &Key,
1191             L"",
1192             L"You are going to leave third Form!",
1193             L"Press ESC or ENTER to continue ...",
1194             L"",
1195             NULL
1196             );
1197         } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));
1198       }
1199 
1200       if (QuestionId == 0x1247) {
1201         Status = InternalStopMonitor ();
1202         ASSERT_EFI_ERROR (Status);
1203       }
1204     }
1205     break;
1206 
1207   case EFI_BROWSER_ACTION_RETRIEVE:
1208     {
1209       switch (QuestionId ) {
1210       case 0x1248:
1211         if (Type != EFI_IFR_TYPE_REF) {
1212           return EFI_INVALID_PARAMETER;
1213         }
1214         Value->ref.FormId = 0x3;
1215         break;
1216 
1217       case 0x5678:
1218       case 0x1247:
1219         //
1220         // We will reach here once the Question is refreshed
1221         //
1222 
1223         //
1224         // Initialize the container for dynamic opcodes
1225         //
1226         StartOpCodeHandle = HiiAllocateOpCodeHandle ();
1227         ASSERT (StartOpCodeHandle != NULL);
1228 
1229         //
1230         // Create Hii Extend Label OpCode as the start opcode
1231         //
1232         StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1233         StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1234         if (QuestionId == 0x5678) {
1235           StartLabel->Number       = LABEL_UPDATE2;
1236           FormId                   = 0x03;
1237           PrivateData->Configuration.DynamicRefresh++;
1238         } else if (QuestionId == 0x1247 ) {
1239           StartLabel->Number       = LABEL_UPDATE3;
1240           FormId                   = 0x06;
1241           PrivateData->Configuration.RefreshGuidCount++;
1242         }
1243 
1244         HiiCreateActionOpCode (
1245           StartOpCodeHandle,                // Container for dynamic created opcodes
1246           0x1237,                           // Question ID
1247           STRING_TOKEN(STR_EXIT_TEXT),      // Prompt text
1248           STRING_TOKEN(STR_EXIT_TEXT),      // Help text
1249           EFI_IFR_FLAG_CALLBACK,            // Question flag
1250           0                                 // Action String ID
1251         );
1252 
1253         HiiUpdateForm (
1254           PrivateData->HiiHandle[0],        // HII handle
1255           &gDriverSampleFormSetGuid,        // Formset GUID
1256           FormId,                           // Form ID
1257           StartOpCodeHandle,                // Label for where to insert opcodes
1258           NULL                              // Insert data
1259         );
1260 
1261         HiiFreeOpCodeHandle (StartOpCodeHandle);
1262 
1263         //
1264         // Refresh the Question value
1265         //
1266         Status = gRT->SetVariable(
1267                         VariableName,
1268                         &gDriverSampleFormSetGuid,
1269                         EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
1270                         sizeof (DRIVER_SAMPLE_CONFIGURATION),
1271                         &PrivateData->Configuration
1272                         );
1273 
1274         if (QuestionId == 0x5678) {
1275           //
1276           // Update uncommitted data of Browser
1277           //
1278           EfiData = AllocateZeroPool (sizeof (MY_EFI_VARSTORE_DATA));
1279           ASSERT (EfiData != NULL);
1280           if (HiiGetBrowserData (&gDriverSampleFormSetGuid, MyEfiVar, sizeof (MY_EFI_VARSTORE_DATA), (UINT8 *) EfiData)) {
1281             EfiData->Field8 = 111;
1282             HiiSetBrowserData (
1283               &gDriverSampleFormSetGuid,
1284               MyEfiVar,
1285               sizeof (MY_EFI_VARSTORE_DATA),
1286               (UINT8 *) EfiData,
1287               NULL
1288             );
1289           }
1290           FreePool (EfiData);
1291         }
1292         break;
1293       }
1294     }
1295     break;
1296 
1297   case EFI_BROWSER_ACTION_DEFAULT_STANDARD:
1298     {
1299       switch (QuestionId) {
1300       case 0x1240:
1301         Value->u8 = DEFAULT_CLASS_STANDARD_VALUE;
1302       break;
1303 
1304       case 0x1252:
1305         for (Index = 0; Index < 3; Index ++) {
1306           SetArrayData (Value, EFI_IFR_TYPE_NUM_SIZE_8, Index, BufferValue--);
1307         }
1308       break;
1309 
1310       case 0x6666:
1311         Value->u8 = 12;
1312         break;
1313 
1314       default:
1315         Status = EFI_UNSUPPORTED;
1316       break;
1317       }
1318     }
1319     break;
1320 
1321   case EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING:
1322     {
1323       switch (QuestionId) {
1324       case 0x1240:
1325         Value->u8 = DEFAULT_CLASS_MANUFACTURING_VALUE;
1326       break;
1327 
1328      case 0x6666:
1329         Value->u8 = 13;
1330         break;
1331 
1332       default:
1333         Status = EFI_UNSUPPORTED;
1334       break;
1335       }
1336     }
1337     break;
1338 
1339   case EFI_BROWSER_ACTION_CHANGING:
1340   {
1341     switch (QuestionId) {
1342     case 0x1249:
1343       {
1344         if (Type != EFI_IFR_TYPE_REF) {
1345           return EFI_INVALID_PARAMETER;
1346         }
1347 
1348         Value->ref.FormId = 0x1234;
1349       }
1350     break;
1351     case 0x1234:
1352       //
1353       // Initialize the container for dynamic opcodes
1354       //
1355       StartOpCodeHandle = HiiAllocateOpCodeHandle ();
1356       ASSERT (StartOpCodeHandle != NULL);
1357 
1358       EndOpCodeHandle = HiiAllocateOpCodeHandle ();
1359       ASSERT (EndOpCodeHandle != NULL);
1360 
1361       //
1362       // Create Hii Extend Label OpCode as the start opcode
1363       //
1364       StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1365       StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1366       StartLabel->Number       = LABEL_UPDATE1;
1367 
1368       //
1369       // Create Hii Extend Label OpCode as the end opcode
1370       //
1371       EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1372       EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1373       EndLabel->Number       = LABEL_END;
1374 
1375       HiiCreateActionOpCode (
1376         StartOpCodeHandle,                // Container for dynamic created opcodes
1377         0x1237,                           // Question ID
1378         STRING_TOKEN(STR_EXIT_TEXT),      // Prompt text
1379         STRING_TOKEN(STR_EXIT_TEXT),      // Help text
1380         EFI_IFR_FLAG_CALLBACK,            // Question flag
1381         0                                 // Action String ID
1382       );
1383 
1384       //
1385       // Create Option OpCode
1386       //
1387       OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
1388       ASSERT (OptionsOpCodeHandle != NULL);
1389 
1390       HiiCreateOneOfOptionOpCode (
1391         OptionsOpCodeHandle,
1392         STRING_TOKEN (STR_BOOT_OPTION1),
1393         0,
1394         EFI_IFR_NUMERIC_SIZE_1,
1395         1
1396         );
1397 
1398       HiiCreateOneOfOptionOpCode (
1399         OptionsOpCodeHandle,
1400         STRING_TOKEN (STR_BOOT_OPTION2),
1401         0,
1402         EFI_IFR_NUMERIC_SIZE_1,
1403         2
1404         );
1405 
1406       //
1407       // Prepare initial value for the dynamic created oneof Question
1408       //
1409       PrivateData->Configuration.DynamicOneof = 2;
1410       Status = gRT->SetVariable(
1411                       VariableName,
1412                       &gDriverSampleFormSetGuid,
1413                       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
1414                       sizeof (DRIVER_SAMPLE_CONFIGURATION),
1415                       &PrivateData->Configuration
1416                       );
1417 
1418       //
1419       // Set initial vlaue of dynamic created oneof Question in Form Browser
1420       //
1421       Configuration = AllocateZeroPool (sizeof (DRIVER_SAMPLE_CONFIGURATION));
1422       ASSERT (Configuration != NULL);
1423       if (HiiGetBrowserData (&gDriverSampleFormSetGuid, VariableName, sizeof (DRIVER_SAMPLE_CONFIGURATION), (UINT8 *) Configuration)) {
1424         Configuration->DynamicOneof = 2;
1425 
1426         //
1427         // Update uncommitted data of Browser
1428         //
1429         HiiSetBrowserData (
1430           &gDriverSampleFormSetGuid,
1431           VariableName,
1432           sizeof (DRIVER_SAMPLE_CONFIGURATION),
1433           (UINT8 *) Configuration,
1434           NULL
1435           );
1436       }
1437       FreePool (Configuration);
1438 
1439       HiiCreateOneOfOpCode (
1440         StartOpCodeHandle,                         // Container for dynamic created opcodes
1441         0x8001,                                    // Question ID (or call it "key")
1442         CONFIGURATION_VARSTORE_ID,                 // VarStore ID
1443         (UINT16) DYNAMIC_ONE_OF_VAR_OFFSET,        // Offset in Buffer Storage
1444         STRING_TOKEN (STR_ONE_OF_PROMPT),          // Question prompt text
1445         STRING_TOKEN (STR_ONE_OF_HELP),            // Question help text
1446         EFI_IFR_FLAG_CALLBACK,                     // Question flag
1447         EFI_IFR_NUMERIC_SIZE_1,                    // Data type of Question Value
1448         OptionsOpCodeHandle,                       // Option Opcode list
1449         NULL                                       // Default Opcode is NULl
1450         );
1451 
1452       HiiCreateOrderedListOpCode (
1453         StartOpCodeHandle,                         // Container for dynamic created opcodes
1454         0x8002,                                    // Question ID
1455         CONFIGURATION_VARSTORE_ID,                 // VarStore ID
1456         (UINT16) DYNAMIC_ORDERED_LIST_VAR_OFFSET,  // Offset in Buffer Storage
1457         STRING_TOKEN (STR_BOOT_OPTIONS),           // Question prompt text
1458         STRING_TOKEN (STR_BOOT_OPTIONS),           // Question help text
1459         EFI_IFR_FLAG_RESET_REQUIRED,               // Question flag
1460         0,                                         // Ordered list flag, e.g. EFI_IFR_UNIQUE_SET
1461         EFI_IFR_NUMERIC_SIZE_1,                    // Data type of Question value
1462         5,                                         // Maximum container
1463         OptionsOpCodeHandle,                       // Option Opcode list
1464         NULL                                       // Default Opcode is NULl
1465         );
1466 
1467       HiiCreateTextOpCode (
1468         StartOpCodeHandle,
1469         STRING_TOKEN(STR_TEXT_SAMPLE_HELP),
1470         STRING_TOKEN(STR_TEXT_SAMPLE_HELP),
1471         STRING_TOKEN(STR_TEXT_SAMPLE_STRING)
1472       );
1473 
1474       HiiCreateDateOpCode (
1475         StartOpCodeHandle,
1476         0x8004,
1477         0x0,
1478         0x0,
1479         STRING_TOKEN(STR_DATE_SAMPLE_HELP),
1480         STRING_TOKEN(STR_DATE_SAMPLE_HELP),
1481         0,
1482         QF_DATE_STORAGE_TIME,
1483         NULL
1484         );
1485 
1486       HiiCreateTimeOpCode (
1487         StartOpCodeHandle,
1488         0x8005,
1489         0x0,
1490         0x0,
1491         STRING_TOKEN(STR_TIME_SAMPLE_HELP),
1492         STRING_TOKEN(STR_TIME_SAMPLE_HELP),
1493         0,
1494         QF_TIME_STORAGE_TIME,
1495         NULL
1496         );
1497 
1498       HiiCreateGotoOpCode (
1499         StartOpCodeHandle,                // Container for dynamic created opcodes
1500         1,                                // Target Form ID
1501         STRING_TOKEN (STR_GOTO_FORM1),    // Prompt text
1502         STRING_TOKEN (STR_GOTO_HELP),     // Help text
1503         0,                                // Question flag
1504         0x8003                            // Question ID
1505         );
1506 
1507       HiiUpdateForm (
1508         PrivateData->HiiHandle[0],  // HII handle
1509         &gDriverSampleFormSetGuid,  // Formset GUID
1510         0x1234,                     // Form ID
1511         StartOpCodeHandle,          // Label for where to insert opcodes
1512         EndOpCodeHandle             // Replace data
1513         );
1514 
1515       HiiFreeOpCodeHandle (StartOpCodeHandle);
1516       HiiFreeOpCodeHandle (OptionsOpCodeHandle);
1517       HiiFreeOpCodeHandle (EndOpCodeHandle);
1518       break;
1519 
1520     default:
1521       break;
1522     }
1523   }
1524   break;
1525 
1526   case EFI_BROWSER_ACTION_CHANGED:
1527     switch (QuestionId) {
1528       case 0x1237:
1529         //
1530         // User press "Exit now", request Browser to exit
1531         //
1532         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
1533         break;
1534 
1535       case 0x1238:
1536         //
1537         // User press "Save now", request Browser to save the uncommitted data.
1538         //
1539         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
1540         break;
1541 
1542       case 0x1241:
1543       case 0x1246:
1544         //
1545         // User press "Submit current form and Exit now", request Browser to submit current form and exit
1546         //
1547         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
1548         break;
1549 
1550       case 0x1242:
1551         //
1552         // User press "Discard current form now", request Browser to discard the uncommitted data.
1553         //
1554         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD;
1555         break;
1556 
1557       case 0x1243:
1558         //
1559         // User press "Submit current form now", request Browser to save the uncommitted data.
1560         //
1561         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
1562         break;
1563 
1564       case 0x1244:
1565       case 0x1245:
1566         //
1567         // User press "Discard current form and Exit now", request Browser to discard the uncommitted data and exit.
1568         //
1569         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
1570         break;
1571 
1572       case 0x1231:
1573         //
1574         // 1. Check to see whether system support keyword.
1575         //
1576         Status = PrivateData->HiiKeywordHandler->GetData (PrivateData->HiiKeywordHandler,
1577                                                           L"NAMESPACE=x-UEFI-ns",
1578                                                           L"KEYWORD=iSCSIBootEnable",
1579                                                           &Progress,
1580                                                           &ProgressErr,
1581                                                           &Results
1582                                                          );
1583         if (EFI_ERROR (Status)) {
1584           do {
1585             CreatePopUp (
1586               EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1587               &Key,
1588               L"",
1589               L"This system not support this keyword!",
1590               L"Press ENTER to continue ...",
1591               L"",
1592               NULL
1593               );
1594           } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1595 
1596           Status = EFI_SUCCESS;
1597           break;
1598         }
1599 
1600         //
1601         // 2. If system support this keyword, just try to change value.
1602         //
1603 
1604         //
1605         // Change value from '0' to '1' or from '1' to '0'
1606         //
1607         TmpStr = StrStr (Results, L"&VALUE=");
1608         ASSERT (TmpStr != NULL);
1609         TmpStr += StrLen (L"&VALUE=");
1610         TmpStr++;
1611         if (*TmpStr == L'0') {
1612           *TmpStr = L'1';
1613         } else {
1614           *TmpStr = L'0';
1615         }
1616 
1617         //
1618         // 3. Call the keyword handler protocol to change the value.
1619         //
1620         Status = PrivateData->HiiKeywordHandler->SetData (PrivateData->HiiKeywordHandler,
1621                                                           Results,
1622                                                           &Progress,
1623                                                           &ProgressErr
1624                                                          );
1625         if (EFI_ERROR (Status)) {
1626           do {
1627             CreatePopUp (
1628               EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1629               &Key,
1630               L"",
1631               L"Set keyword to the system failed!",
1632               L"Press ENTER to continue ...",
1633               L"",
1634               NULL
1635               );
1636           } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1637 
1638           Status = EFI_SUCCESS;
1639           break;
1640         }
1641         break;
1642 
1643       case 0x1330:
1644         Status = mPrivateData->HiiPopup->CreatePopup (
1645           mPrivateData->HiiPopup,
1646           EfiHiiPopupStyleInfo,
1647           EfiHiiPopupTypeYesNo,
1648           mPrivateData->HiiHandle[0],
1649           STRING_TOKEN (STR_POPUP_STRING),
1650           &UserSelection
1651           );
1652         if (!EFI_ERROR (Status)) {
1653           if (UserSelection == EfiHiiPopupSelectionYes) {
1654             *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
1655           }
1656         }
1657         break;
1658 
1659       default:
1660       break;
1661     }
1662   break;
1663 
1664   case EFI_BROWSER_ACTION_SUBMITTED:
1665     {
1666       if (QuestionId == 0x1250) {
1667         //
1668         // Sample CallBack for EFI_BROWSER_ACTION_SUBMITTED action:
1669         // Show up a pop-up to show SUBMITTED callback has been triggered.
1670         //
1671         do {
1672           CreatePopUp (
1673             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1674             &Key,
1675             L"",
1676             L"EfiVarstore value has been submitted!",
1677             L"Press ESC or ENTER to continue ...",
1678             L"",
1679             NULL
1680             );
1681         } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));
1682       }
1683     }
1684     break;
1685 
1686   default:
1687     Status = EFI_UNSUPPORTED;
1688     break;
1689   }
1690 
1691   return Status;
1692 }
1693 
1694 /**
1695   Main entry for this driver.
1696 
1697   @param ImageHandle     Image handle this driver.
1698   @param SystemTable     Pointer to SystemTable.
1699 
1700   @retval EFI_SUCESS     This function always complete successfully.
1701 
1702 **/
1703 EFI_STATUS
1704 EFIAPI
DriverSampleInit(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1705 DriverSampleInit (
1706   IN EFI_HANDLE                   ImageHandle,
1707   IN EFI_SYSTEM_TABLE             *SystemTable
1708   )
1709 {
1710   EFI_STATUS                      Status;
1711   EFI_HII_HANDLE                  HiiHandle[2];
1712   EFI_SCREEN_DESCRIPTOR           Screen;
1713   EFI_HII_DATABASE_PROTOCOL       *HiiDatabase;
1714   EFI_HII_STRING_PROTOCOL         *HiiString;
1715   EFI_FORM_BROWSER2_PROTOCOL      *FormBrowser2;
1716   EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
1717   EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *HiiKeywordHandler;
1718   EFI_HII_POPUP_PROTOCOL              *PopupHandler;
1719   CHAR16                          *NewString;
1720   UINTN                           BufferSize;
1721   DRIVER_SAMPLE_CONFIGURATION     *Configuration;
1722   BOOLEAN                         ActionFlag;
1723   EFI_STRING                      ConfigRequestHdr;
1724   EFI_STRING                      NameRequestHdr;
1725   MY_EFI_VARSTORE_DATA            *VarStoreConfig;
1726   MY_EFI_BITS_VARSTORE_DATA       *BitsVarStoreConfig;
1727   MY_EFI_UNION_DATA               *UnionConfig;
1728   EFI_INPUT_KEY                   HotKey;
1729   EDKII_FORM_BROWSER_EXTENSION_PROTOCOL *FormBrowserEx;
1730 
1731   //
1732   // Initialize the local variables.
1733   //
1734   ConfigRequestHdr = NULL;
1735   NewString        = NULL;
1736 
1737   //
1738   // Initialize screen dimensions for SendForm().
1739   // Remove 3 characters from top and bottom
1740   //
1741   ZeroMem (&Screen, sizeof (EFI_SCREEN_DESCRIPTOR));
1742   gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Screen.RightColumn, &Screen.BottomRow);
1743 
1744   Screen.TopRow     = 3;
1745   Screen.BottomRow  = Screen.BottomRow - 3;
1746 
1747   //
1748   // Initialize driver private data
1749   //
1750   mPrivateData = AllocateZeroPool (sizeof (DRIVER_SAMPLE_PRIVATE_DATA));
1751   if (mPrivateData == NULL) {
1752     return EFI_OUT_OF_RESOURCES;
1753   }
1754 
1755   mPrivateData->Signature = DRIVER_SAMPLE_PRIVATE_SIGNATURE;
1756 
1757   mPrivateData->ConfigAccess.ExtractConfig = ExtractConfig;
1758   mPrivateData->ConfigAccess.RouteConfig = RouteConfig;
1759   mPrivateData->ConfigAccess.Callback = DriverCallback;
1760 
1761   //
1762   // Locate Hii Database protocol
1763   //
1764   Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &HiiDatabase);
1765   if (EFI_ERROR (Status)) {
1766     return Status;
1767   }
1768   mPrivateData->HiiDatabase = HiiDatabase;
1769 
1770   //
1771   // Locate HiiString protocol
1772   //
1773   Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString);
1774   if (EFI_ERROR (Status)) {
1775     return Status;
1776   }
1777   mPrivateData->HiiString = HiiString;
1778 
1779   //
1780   // Locate Formbrowser2 protocol
1781   //
1782   Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
1783   if (EFI_ERROR (Status)) {
1784     return Status;
1785   }
1786   mPrivateData->FormBrowser2 = FormBrowser2;
1787 
1788   //
1789   // Locate ConfigRouting protocol
1790   //
1791   Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
1792   if (EFI_ERROR (Status)) {
1793     return Status;
1794   }
1795   mPrivateData->HiiConfigRouting = HiiConfigRouting;
1796 
1797   //
1798   // Locate keyword handler protocol
1799   //
1800   Status = gBS->LocateProtocol (&gEfiConfigKeywordHandlerProtocolGuid, NULL, (VOID **) &HiiKeywordHandler);
1801   if (EFI_ERROR (Status)) {
1802     return Status;
1803   }
1804   mPrivateData->HiiKeywordHandler = HiiKeywordHandler;
1805 
1806   //
1807   // Locate HiiPopup protocol
1808   //
1809   Status = gBS->LocateProtocol (&gEfiHiiPopupProtocolGuid, NULL, (VOID **) &PopupHandler);
1810   if (EFI_ERROR (Status)) {
1811     return Status;
1812   }
1813   mPrivateData->HiiPopup = PopupHandler;
1814 
1815   Status = gBS->InstallMultipleProtocolInterfaces (
1816                   &DriverHandle[0],
1817                   &gEfiDevicePathProtocolGuid,
1818                   &mHiiVendorDevicePath0,
1819                   &gEfiHiiConfigAccessProtocolGuid,
1820                   &mPrivateData->ConfigAccess,
1821                   NULL
1822                   );
1823   ASSERT_EFI_ERROR (Status);
1824 
1825   mPrivateData->DriverHandle[0] = DriverHandle[0];
1826 
1827   //
1828   // Publish our HII data
1829   //
1830   HiiHandle[0] = HiiAddPackages (
1831                    &gDriverSampleFormSetGuid,
1832                    DriverHandle[0],
1833                    DriverSampleStrings,
1834                    VfrBin,
1835                    NULL
1836                    );
1837   if (HiiHandle[0] == NULL) {
1838     return EFI_OUT_OF_RESOURCES;
1839   }
1840 
1841   mPrivateData->HiiHandle[0] = HiiHandle[0];
1842 
1843   //
1844   // Publish another Fromset
1845   //
1846   Status = gBS->InstallMultipleProtocolInterfaces (
1847                   &DriverHandle[1],
1848                   &gEfiDevicePathProtocolGuid,
1849                   &mHiiVendorDevicePath1,
1850                   &gEfiHiiConfigAccessProtocolGuid,
1851                   &mPrivateData->ConfigAccess,
1852                   NULL
1853                   );
1854   ASSERT_EFI_ERROR (Status);
1855 
1856   mPrivateData->DriverHandle[1] = DriverHandle[1];
1857 
1858   HiiHandle[1] = HiiAddPackages (
1859                    &gDriverSampleInventoryGuid,
1860                    DriverHandle[1],
1861                    DriverSampleStrings,
1862                    InventoryBin,
1863                    NULL
1864                    );
1865   if (HiiHandle[1] == NULL) {
1866     DriverSampleUnload (ImageHandle);
1867     return EFI_OUT_OF_RESOURCES;
1868   }
1869 
1870   mPrivateData->HiiHandle[1] = HiiHandle[1];
1871 
1872   //
1873   // Update the device path string.
1874   //
1875   NewString = ConvertDevicePathToText((EFI_DEVICE_PATH_PROTOCOL*)&mHiiVendorDevicePath0, FALSE, FALSE);
1876   if (HiiSetString (HiiHandle[0], STRING_TOKEN (STR_DEVICE_PATH), NewString, NULL) == 0) {
1877     DriverSampleUnload (ImageHandle);
1878     return EFI_OUT_OF_RESOURCES;
1879   }
1880   if (NewString != NULL) {
1881     FreePool (NewString);
1882   }
1883 
1884   //
1885   // Very simple example of how one would update a string that is already
1886   // in the HII database
1887   //
1888   NewString = L"700 Mhz";
1889 
1890   if (HiiSetString (HiiHandle[0], STRING_TOKEN (STR_CPU_STRING2), NewString, NULL) == 0) {
1891     DriverSampleUnload (ImageHandle);
1892     return EFI_OUT_OF_RESOURCES;
1893   }
1894 
1895   HiiSetString (HiiHandle[0], 0, NewString, NULL);
1896 
1897   //
1898   // Initialize Name/Value name String ID
1899   //
1900   mPrivateData->NameStringId[0] = STR_NAME_VALUE_VAR_NAME0;
1901   mPrivateData->NameStringId[1] = STR_NAME_VALUE_VAR_NAME1;
1902   mPrivateData->NameStringId[2] = STR_NAME_VALUE_VAR_NAME2;
1903 
1904   //
1905   // Initialize configuration data
1906   //
1907   Configuration = &mPrivateData->Configuration;
1908   ZeroMem (Configuration, sizeof (DRIVER_SAMPLE_CONFIGURATION));
1909 
1910   //
1911   // Try to read NV config EFI variable first
1912   //
1913   ConfigRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, VariableName, DriverHandle[0]);
1914   ASSERT (ConfigRequestHdr != NULL);
1915 
1916   NameRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, NULL, DriverHandle[0]);
1917   ASSERT (NameRequestHdr != NULL);
1918 
1919   BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
1920   Status = gRT->GetVariable (VariableName, &gDriverSampleFormSetGuid, NULL, &BufferSize, Configuration);
1921   if (EFI_ERROR (Status)) {
1922     //
1923     // Store zero data Buffer Storage to EFI variable
1924     //
1925     Status = gRT->SetVariable(
1926                     VariableName,
1927                     &gDriverSampleFormSetGuid,
1928                     EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
1929                     sizeof (DRIVER_SAMPLE_CONFIGURATION),
1930                     Configuration
1931                     );
1932     if (EFI_ERROR (Status)) {
1933       DriverSampleUnload (ImageHandle);
1934       return Status;
1935     }
1936     //
1937     // EFI variable for NV config doesn't exit, we should build this variable
1938     // based on default values stored in IFR
1939     //
1940     ActionFlag = HiiSetToDefaults (NameRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD);
1941     if (!ActionFlag) {
1942       DriverSampleUnload (ImageHandle);
1943       return EFI_INVALID_PARAMETER;
1944     }
1945 
1946     ActionFlag = HiiSetToDefaults (ConfigRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD);
1947     if (!ActionFlag) {
1948       DriverSampleUnload (ImageHandle);
1949       return EFI_INVALID_PARAMETER;
1950     }
1951   } else {
1952     //
1953     // EFI variable does exist and Validate Current Setting
1954     //
1955     ActionFlag = HiiValidateSettings (NameRequestHdr);
1956     if (!ActionFlag) {
1957       DriverSampleUnload (ImageHandle);
1958       return EFI_INVALID_PARAMETER;
1959     }
1960 
1961     ActionFlag = HiiValidateSettings (ConfigRequestHdr);
1962     if (!ActionFlag) {
1963       DriverSampleUnload (ImageHandle);
1964       return EFI_INVALID_PARAMETER;
1965     }
1966   }
1967   FreePool (ConfigRequestHdr);
1968 
1969   //
1970   // Initialize efi varstore configuration data
1971   //
1972   VarStoreConfig = &mPrivateData->VarStoreConfig;
1973   ZeroMem (VarStoreConfig, sizeof (MY_EFI_VARSTORE_DATA));
1974 
1975   ConfigRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, MyEfiVar, DriverHandle[0]);
1976   ASSERT (ConfigRequestHdr != NULL);
1977 
1978   BufferSize = sizeof (MY_EFI_VARSTORE_DATA);
1979   Status = gRT->GetVariable (MyEfiVar, &gDriverSampleFormSetGuid, NULL, &BufferSize, VarStoreConfig);
1980   if (EFI_ERROR (Status)) {
1981     //
1982     // Store zero data to EFI variable Storage.
1983     //
1984     Status = gRT->SetVariable(
1985                     MyEfiVar,
1986                     &gDriverSampleFormSetGuid,
1987                     EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
1988                     sizeof (MY_EFI_VARSTORE_DATA),
1989                     VarStoreConfig
1990                     );
1991     if (EFI_ERROR (Status)) {
1992       DriverSampleUnload (ImageHandle);
1993       return Status;
1994     }
1995     //
1996     // EFI variable for NV config doesn't exit, we should build this variable
1997     // based on default values stored in IFR
1998     //
1999     ActionFlag = HiiSetToDefaults (ConfigRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD);
2000     if (!ActionFlag) {
2001       DriverSampleUnload (ImageHandle);
2002       return EFI_INVALID_PARAMETER;
2003     }
2004   } else {
2005     //
2006     // EFI variable does exist and Validate Current Setting
2007     //
2008     ActionFlag = HiiValidateSettings (ConfigRequestHdr);
2009     if (!ActionFlag) {
2010       DriverSampleUnload (ImageHandle);
2011       return EFI_INVALID_PARAMETER;
2012     }
2013   }
2014   FreePool (ConfigRequestHdr);
2015 
2016   //
2017   // Initialize Bits efi varstore configuration data
2018   //
2019   BitsVarStoreConfig = &mPrivateData->BitsVarStoreConfig;
2020   ZeroMem (BitsVarStoreConfig, sizeof (MY_EFI_BITS_VARSTORE_DATA));
2021 
2022   ConfigRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, MyEfiBitVar, DriverHandle[0]);
2023   ASSERT (ConfigRequestHdr != NULL);
2024 
2025   BufferSize = sizeof (MY_EFI_BITS_VARSTORE_DATA);
2026   Status = gRT->GetVariable (MyEfiBitVar, &gDriverSampleFormSetGuid, NULL, &BufferSize, BitsVarStoreConfig);
2027   if (EFI_ERROR (Status)) {
2028     //
2029     // Store zero data to EFI variable Storage.
2030     //
2031     Status = gRT->SetVariable(
2032                     MyEfiBitVar,
2033                     &gDriverSampleFormSetGuid,
2034                     EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
2035                     sizeof (MY_EFI_BITS_VARSTORE_DATA),
2036                     BitsVarStoreConfig
2037                     );
2038     if (EFI_ERROR (Status)) {
2039       DriverSampleUnload (ImageHandle);
2040       return Status;
2041     }
2042     //
2043     // EFI variable for NV config doesn't exit, we should build this variable
2044     // based on default values stored in IFR
2045     //
2046     ActionFlag = HiiSetToDefaults (ConfigRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD);
2047     if (!ActionFlag) {
2048       DriverSampleUnload (ImageHandle);
2049       return EFI_INVALID_PARAMETER;
2050     }
2051   } else {
2052     //
2053     // EFI variable does exist and Validate Current Setting
2054     //
2055     ActionFlag = HiiValidateSettings (ConfigRequestHdr);
2056     if (!ActionFlag) {
2057       DriverSampleUnload (ImageHandle);
2058       return EFI_INVALID_PARAMETER;
2059     }
2060   }
2061   FreePool (ConfigRequestHdr);
2062 
2063    //
2064   // Initialize Union efi varstore configuration data
2065   //
2066   UnionConfig = &mPrivateData->UnionConfig;
2067   ZeroMem (UnionConfig, sizeof (MY_EFI_UNION_DATA));
2068 
2069   ConfigRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, MyEfiUnionVar, DriverHandle[0]);
2070   ASSERT (ConfigRequestHdr != NULL);
2071 
2072   BufferSize = sizeof (MY_EFI_UNION_DATA);
2073   Status = gRT->GetVariable (MyEfiUnionVar, &gDriverSampleFormSetGuid, NULL, &BufferSize, UnionConfig);
2074   if (EFI_ERROR (Status)) {
2075     //
2076     // Store zero data to EFI variable Storage.
2077     //
2078     Status = gRT->SetVariable(
2079                     MyEfiUnionVar,
2080                     &gDriverSampleFormSetGuid,
2081                     EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
2082                     sizeof (MY_EFI_UNION_DATA),
2083                     UnionConfig
2084                     );
2085     if (EFI_ERROR (Status)) {
2086       DriverSampleUnload (ImageHandle);
2087       return Status;
2088     }
2089     //
2090     // EFI variable for NV config doesn't exit, we should build this variable
2091     // based on default values stored in IFR
2092     //
2093     ActionFlag = HiiSetToDefaults (ConfigRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD);
2094     if (!ActionFlag) {
2095       DriverSampleUnload (ImageHandle);
2096       return EFI_INVALID_PARAMETER;
2097     }
2098   } else {
2099     //
2100     // EFI variable does exist and Validate Current Setting
2101     //
2102     ActionFlag = HiiValidateSettings (ConfigRequestHdr);
2103     if (!ActionFlag) {
2104       DriverSampleUnload (ImageHandle);
2105       return EFI_INVALID_PARAMETER;
2106     }
2107   }
2108   FreePool (ConfigRequestHdr);
2109 
2110   Status = gBS->CreateEventEx (
2111         EVT_NOTIFY_SIGNAL,
2112         TPL_NOTIFY,
2113         EfiEventEmptyFunction,
2114         NULL,
2115         &gEfiIfrRefreshIdOpGuid,
2116         &mEvent
2117         );
2118   ASSERT_EFI_ERROR (Status);
2119 
2120   //
2121   // Example of how to use BrowserEx protocol to register HotKey.
2122   //
2123   Status = gBS->LocateProtocol (&gEdkiiFormBrowserExProtocolGuid, NULL, (VOID **) &FormBrowserEx);
2124   if (!EFI_ERROR (Status)) {
2125     //
2126     // First unregister the default hot key F9 and F10.
2127     //
2128     HotKey.UnicodeChar = CHAR_NULL;
2129     HotKey.ScanCode    = SCAN_F9;
2130     FormBrowserEx->RegisterHotKey (&HotKey, 0, 0, NULL);
2131     HotKey.ScanCode    = SCAN_F10;
2132     FormBrowserEx->RegisterHotKey (&HotKey, 0, 0, NULL);
2133 
2134     //
2135     // Register the default HotKey F9 and F10 again.
2136     //
2137     HotKey.ScanCode   = SCAN_F10;
2138     NewString         = HiiGetString (mPrivateData->HiiHandle[0], STRING_TOKEN (FUNCTION_TEN_STRING), NULL);
2139     ASSERT (NewString != NULL);
2140     FormBrowserEx->RegisterHotKey (&HotKey, BROWSER_ACTION_SUBMIT, 0, NewString);
2141     HotKey.ScanCode   = SCAN_F9;
2142     NewString         = HiiGetString (mPrivateData->HiiHandle[0], STRING_TOKEN (FUNCTION_NINE_STRING), NULL);
2143     ASSERT (NewString != NULL);
2144     FormBrowserEx->RegisterHotKey (&HotKey, BROWSER_ACTION_DEFAULT, EFI_HII_DEFAULT_CLASS_STANDARD, NewString);
2145   }
2146 
2147   //
2148   // In default, this driver is built into Flash device image,
2149   // the following code doesn't run.
2150   //
2151 
2152   //
2153   // Example of how to display only the item we sent to HII
2154   // When this driver is not built into Flash device image,
2155   // it need to call SendForm to show front page by itself.
2156   //
2157   if (DISPLAY_ONLY_MY_ITEM <= 1) {
2158     //
2159     // Have the browser pull out our copy of the data, and only display our data
2160     //
2161     Status = FormBrowser2->SendForm (
2162                              FormBrowser2,
2163                              &(HiiHandle[DISPLAY_ONLY_MY_ITEM]),
2164                              1,
2165                              NULL,
2166                              0,
2167                              NULL,
2168                              NULL
2169                              );
2170 
2171     HiiRemovePackages (HiiHandle[0]);
2172 
2173     HiiRemovePackages (HiiHandle[1]);
2174   }
2175 
2176   return EFI_SUCCESS;
2177 }
2178 
2179 /**
2180   Unloads the application and its installed protocol.
2181 
2182   @param[in]  ImageHandle       Handle that identifies the image to be unloaded.
2183 
2184   @retval EFI_SUCCESS           The image has been unloaded.
2185 **/
2186 EFI_STATUS
2187 EFIAPI
DriverSampleUnload(IN EFI_HANDLE ImageHandle)2188 DriverSampleUnload (
2189   IN EFI_HANDLE  ImageHandle
2190   )
2191 {
2192   UINTN Index;
2193 
2194   ASSERT (mPrivateData != NULL);
2195 
2196   if (DriverHandle[0] != NULL) {
2197     gBS->UninstallMultipleProtocolInterfaces (
2198             DriverHandle[0],
2199             &gEfiDevicePathProtocolGuid,
2200             &mHiiVendorDevicePath0,
2201             &gEfiHiiConfigAccessProtocolGuid,
2202             &mPrivateData->ConfigAccess,
2203             NULL
2204            );
2205     DriverHandle[0] = NULL;
2206   }
2207 
2208   if (DriverHandle[1] != NULL) {
2209     gBS->UninstallMultipleProtocolInterfaces (
2210             DriverHandle[1],
2211             &gEfiDevicePathProtocolGuid,
2212             &mHiiVendorDevicePath1,
2213             &gEfiHiiConfigAccessProtocolGuid,
2214             &mPrivateData->ConfigAccess,
2215             NULL
2216            );
2217     DriverHandle[1] = NULL;
2218   }
2219 
2220   if (mPrivateData->HiiHandle[0] != NULL) {
2221     HiiRemovePackages (mPrivateData->HiiHandle[0]);
2222   }
2223 
2224   if (mPrivateData->HiiHandle[1] != NULL) {
2225     HiiRemovePackages (mPrivateData->HiiHandle[1]);
2226   }
2227 
2228   for (Index = 0; Index < NAME_VALUE_NAME_NUMBER; Index++) {
2229     if (mPrivateData->NameValueName[Index] != NULL) {
2230       FreePool (mPrivateData->NameValueName[Index]);
2231     }
2232   }
2233   FreePool (mPrivateData);
2234   mPrivateData = NULL;
2235 
2236   gBS->CloseEvent (mEvent);
2237 
2238   return EFI_SUCCESS;
2239 }
2240