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