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