2 Copyright (c) 2006, Intel Corporation
3 All rights reserved. This program and the accompanying materials
4 are licensed and made available under the terms and conditions of the BSD License
5 which accompanies this distribution. The full text of the license may be found at
6 http://opensource.org/licenses/bsd-license.php
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 This is an example of how a driver might export data to the HII protocol to be
17 later utilized by the Setup Protocol
21 #include "DriverSample.h"
23 #define DISPLAY_ONLY_MY_ITEM 0x0001
25 #define STRING_PACK_GUID \
27 0x8160a85f, 0x934d, 0x468b, { 0xa2, 0x35, 0x72, 0x89, 0x59, 0x14, 0xf6, 0xfc } \
30 EFI_GUID mFormSetGuid
= FORMSET_GUID
;
31 EFI_GUID mStringPackGuid
= STRING_PACK_GUID
;
36 IN EFI_FORM_CALLBACK_PROTOCOL
*This
,
38 IN EFI_IFR_DATA_ARRAY
*Data
,
39 OUT EFI_HII_CALLBACK_PACKET
**Packet
45 This is the function that is called to provide results data to the driver. This data
46 consists of a unique key which is used to identify what data is either being passed back
51 KeyValue - A unique value which is sent to the original exporting driver so that it
52 can identify the type of data to expect. The format of the data tends to
53 vary based on the op-code that geerated the callback.
55 Data - A pointer to the data being sent to the original exporting driver.
61 EFI_CALLBACK_INFO
*Private
;
62 EFI_HII_UPDATE_DATA
*UpdateData
;
65 EFI_HII_CALLBACK_PACKET
*DataPacket
;
67 CHAR16 VariableName
[40];
68 STATIC UINT16 QuestionId
= 0;
69 IFR_OPTION
*OptionList
;
73 Private
= EFI_CALLBACK_INFO_FROM_THIS (This
);
76 // This should tell me the first offset AFTER the end of the compiled NV map
77 // If op-code results are not going to be saved to NV locations ensure the QuestionId
78 // is beyond the end of the NVRAM mapping.
80 if (QuestionId
== 0) {
81 QuestionId
= sizeof (MyIfrNVData
);
84 ZeroMem (VariableName
, (sizeof (CHAR16
) * 40));
89 // Create a small boot order list
91 QuestionId
= (UINT16
) ((UINTN
) (&NVStruc
.BootOrder
) - (UINTN
) (&NVStruc
));
94 // Need some memory for OptionList. Allow for up to 8 options.
96 OptionList
= AllocateZeroPool (sizeof (IFR_OPTION
) * 8);
99 // Allocate space for creation of Buffer
101 UpdateData
= AllocateZeroPool (0x1000);
104 // Remove all the op-codes starting with Label 0x2222 to next Label (second label is for convenience
105 // so we don't have to keep track of how many op-codes we added or subtracted. The rules for removal
106 // of op-codes are simply that the removal will always stop as soon as a label or the end of a form is
107 // encountered. Therefore, giving a large obnoxious count such as below takes care of other complexities.
109 UpdateData
->DataCount
= 0xFF;
112 // Delete set of op-codes
114 Private
->Hii
->UpdateForm (
116 Private
->RegisteredHandle
,
117 (EFI_FORM_LABEL
) 0x2222,
118 FALSE
, // If we aren't adding, we are deleting
125 for (Index
= 0; Index
< 3; Index
++) {
126 OptionList
[Index
].StringToken
= (UINT16
) (STR_BOOT_OPTION1
+ Index
);
127 OptionList
[Index
].Value
= (UINT16
) (Index
+ 1);
128 OptionList
[Index
].Flags
= RESET_REQUIRED
;
131 CreateOrderedListOpCode (
132 QuestionId
, // Question ID
134 (UINT16
) STRING_TOKEN (STR_BOOT_OPTIONS
), // Token value for the Prompt
135 (UINT16
) STRING_TOKEN (STR_NULL_STRING
), // Token value for the Help
138 &UpdateData
->Data
// Buffer location to place op-codes
142 // For one-of/ordered lists commands, they really consist of 2 op-codes (a header and a footer)
143 // Each option within a one-of/ordered list is also an op-code
144 // So this example has 5 op-codes it is adding since we have a one-of header + 3 options + one-of footer
146 UpdateData
->DataCount
= 0x5;
151 Private
->Hii
->UpdateForm (
153 Private
->RegisteredHandle
,
154 (EFI_FORM_LABEL
) 0x2222,
159 gBS
->FreePool (UpdateData
);
160 gBS
->FreePool (OptionList
);
165 // Create a large boot order list
167 QuestionId
= (UINT16
) ((UINTN
) (&NVStruc
.BootOrder
) - (UINTN
) (&NVStruc
));
170 // Need some memory for OptionList. Allow for up to 8 options.
172 OptionList
= AllocateZeroPool (sizeof (IFR_OPTION
) * 8);
175 // Allocate space for creation of Buffer
177 UpdateData
= AllocateZeroPool (0x1000);
180 // Remove all the op-codes starting with Label 0x2222 to next Label (second label is for convenience
181 // so we don't have to keep track of how many op-codes we added or subtracted
183 UpdateData
->DataCount
= 0xFF;
186 // Delete one op-code
188 Private
->Hii
->UpdateForm (
190 Private
->RegisteredHandle
,
191 (EFI_FORM_LABEL
) 0x2222,
199 for (Index
= 0; Index
< 4; Index
++) {
200 OptionList
[Index
].StringToken
= (UINT16
) (STR_BOOT_OPTION1
+ Index
);
201 OptionList
[Index
].Value
= (UINT16
) (Index
+ 1);
202 OptionList
[Index
].Flags
= RESET_REQUIRED
;
205 CreateOrderedListOpCode (
206 QuestionId
, // Question ID
208 (UINT16
) STRING_TOKEN (STR_BOOT_OPTIONS
), // Token value for the Prompt
209 (UINT16
) STRING_TOKEN (STR_NULL_STRING
), // Token value for the Help
212 &UpdateData
->Data
// Buffer location to place op-codes
216 // For one-of commands, they really consist of 2 op-codes (a header and a footer)
217 // Each option within a one-of is also an op-code
218 // So this example has 6 op-codes it is adding since we have a one-of header + 4 options + one-of footer
220 UpdateData
->DataCount
= 0x6;
225 Private
->Hii
->UpdateForm (
227 Private
->RegisteredHandle
,
228 (EFI_FORM_LABEL
) 0x2222,
233 gBS
->FreePool (UpdateData
);
234 gBS
->FreePool (OptionList
);
239 // Allocate space for creation of Buffer
241 QuestionId
= (UINT16
) ((UINTN
) (&NVStruc
.DynamicCheck
));
242 Status
= gBS
->AllocatePool (
245 (VOID
**) &UpdateData
248 ZeroMem (UpdateData
, 0x1000);
250 Location
= (UINT8
*) &UpdateData
->Data
;
252 UpdateData
->FormSetUpdate
= TRUE
;
253 UpdateData
->FormCallbackHandle
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) Private
->CallbackHandle
;
254 UpdateData
->FormUpdate
= FALSE
;
255 UpdateData
->FormTitle
= 0;
256 UpdateData
->DataCount
= 2;
260 STR_GOTO_FORM1
, // Token value for the Prompt
264 &UpdateData
->Data
// Buffer location to place op-codes
267 Location
= Location
+ ((EFI_IFR_OP_HEADER
*) &UpdateData
->Data
)->Length
;
269 CreateCheckBoxOpCode (
270 QuestionId
, // Question ID
271 1, // Data width (BOOLEAN = 1)
272 (UINT16
) STRING_TOKEN (STR_CHECK_DYNAMIC_PROMPT
), // Token value for the Prompt
273 (UINT16
) STRING_TOKEN (STR_CHECK_DYNAMIC_HELP
), // Token value for the Help
274 EFI_IFR_FLAG_INTERACTIVE
, // Flags
276 Location
// Buffer location to place op-codes
279 Private
->Hii
->UpdateForm (
281 Private
->RegisteredHandle
,
282 (EFI_FORM_LABEL
) 0x1234,
287 gBS
->FreePool (UpdateData
);
293 // Allocate space for creation of Buffer
295 Status
= gBS
->AllocatePool (
301 ZeroMem (UpdateData
, 0x1000);
304 // Initialize DataPacket with information intended to remove all
305 // previously created op-codes in the dynamic page
307 UpdateData
->FormSetUpdate
= FALSE
;
308 UpdateData
->FormCallbackHandle
= 0;
309 UpdateData
->FormUpdate
= FALSE
;
310 UpdateData
->FormTitle
= 0;
312 // Unlikely to be more than 0xff op-codes in the dynamic page to remove
314 UpdateData
->DataCount
= 0xff;
315 UpdateData
->Data
= NULL
;
318 // Remove all op-codes from dynamic page
320 Private
->Hii
->UpdateForm (
322 Private
->RegisteredHandle
,
323 (EFI_FORM_LABEL
) 0x1234, // Label 0x1234
324 FALSE
, // Remove Op-codes (will never remove form/endform)
325 UpdateData
// Significant value is UpdateData->DataCount
328 UpdateData
->FormSetUpdate
= FALSE
;
329 UpdateData
->FormCallbackHandle
= 0;
330 UpdateData
->FormUpdate
= FALSE
;
331 UpdateData
->FormTitle
= 0;
332 UpdateData
->DataCount
= 1;
336 STR_GOTO_FORM1
, // Token value for the Prompt
340 &UpdateData
->Data
// Buffer location to place op-codes
343 Private
->Hii
->UpdateForm (
345 Private
->RegisteredHandle
,
346 (EFI_FORM_LABEL
) 0x1234,
351 gBS
->FreePool (UpdateData
);
356 // If I hit the checkbox, I enter this case statement...
359 // Since I am returning an error (for test purposes) I need to pass in the string for the error
360 // I will allocate space for the return value. If an error occurs (which is the case) I can simply return
361 // an error and fill in the string parameter, otherwise, I will return information in the DataArray structure.
362 // The browser will free this packet structure
364 Status
= gBS
->AllocatePool (
366 sizeof (EFI_HII_CALLBACK_PACKET
) + sizeof (SAMPLE_STRING
) + 2,
370 ZeroMem (*Packet
, sizeof (EFI_HII_CALLBACK_PACKET
) + sizeof (SAMPLE_STRING
) + 2);
373 // Assign the buffer address to DataPacket
375 DataPacket
= *Packet
;
377 StrCpy (DataPacket
->String
, (CHAR16
*) SAMPLE_STRING
);
378 return EFI_DEVICE_ERROR
;
382 Status
= gBS
->AllocatePool (
384 sizeof (EFI_HII_CALLBACK_PACKET
) + 2,
388 ZeroMem (*Packet
, sizeof (EFI_HII_CALLBACK_PACKET
) + 2);
391 // Assign the buffer address to DataPacket
393 DataPacket
= *Packet
;
395 DataPacket
->DataArray
.EntryCount
= 1;
396 DataPacket
->DataArray
.NvRamMap
= NULL
;
397 ((EFI_IFR_DATA_ENTRY
*) (&DataPacket
->DataArray
+ 1))->Flags
= EXIT_REQUIRED
;
402 UnicodeSPrint (VariableName
, 0x80, (CHAR16
*) L
"%d", VAR_EQ_TEST_NAME
);
404 Status
= gRT
->SetVariable (
407 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
415 UnicodeSPrint (VariableName
, 0x80, (CHAR16
*) L
"%d", VAR_EQ_TEST_NAME
);
417 Status
= gRT
->SetVariable (
420 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
428 UnicodeSPrint (VariableName
, 0x80, (CHAR16
*) L
"%d", VAR_EQ_TEST_NAME
);
430 Status
= gRT
->SetVariable (
433 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
449 IN EFI_HANDLE ImageHandle
,
450 IN EFI_SYSTEM_TABLE
*SystemTable
454 EFI_HII_PROTOCOL
*Hii
;
456 // EFI_FORM_BROWSER_PROTOCOL *FormConfig;
458 EFI_HII_PACKAGES
*PackageList
;
459 EFI_HII_HANDLE HiiHandle
;
460 STRING_REF TokenToUpdate
;
461 STRING_REF TokenToUpdate2
;
462 STRING_REF TokenToUpdate3
;
464 EFI_HII_UPDATE_DATA
*UpdateData
;
465 EFI_CALLBACK_INFO
*CallbackInfo
;
467 EFI_SCREEN_DESCRIPTOR Screen
;
469 ZeroMem (&Screen
, sizeof (EFI_SCREEN_DESCRIPTOR
));
471 gST
->ConOut
->QueryMode (gST
->ConOut
, gST
->ConOut
->Mode
->Mode
, &Screen
.RightColumn
, &Screen
.BottomRow
);
474 // Remove 3 characters from top and bottom
477 Screen
.BottomRow
= Screen
.BottomRow
- 3;
480 // There should only be one HII protocol
482 Status
= gBS
->LocateProtocol (
483 &gEfiHiiProtocolGuid
,
487 if (EFI_ERROR (Status
)) {
493 // There should only be one Form Configuration protocol
495 Status = gBS->LocateProtocol (
496 &gEfiFormBrowserProtocolGuid,
500 if (EFI_ERROR (Status)) {
504 Status
= gBS
->AllocatePool (
506 sizeof (EFI_CALLBACK_INFO
),
507 (VOID
**) &CallbackInfo
509 if (EFI_ERROR (Status
)) {
513 CallbackInfo
->Signature
= EFI_CALLBACK_INFO_SIGNATURE
;
514 CallbackInfo
->Hii
= Hii
;
517 // This example does not implement worker functions for the NV accessor functions. Only a callback evaluator
519 CallbackInfo
->DriverCallback
.NvRead
= NULL
;
520 CallbackInfo
->DriverCallback
.NvWrite
= NULL
;
521 CallbackInfo
->DriverCallback
.Callback
= DriverCallback
;
524 // Install protocol interface
527 Status
= gBS
->InstallProtocolInterface (
529 &gEfiFormCallbackProtocolGuid
,
530 EFI_NATIVE_INTERFACE
,
531 &CallbackInfo
->DriverCallback
534 ASSERT_EFI_ERROR (Status
);
536 CallbackInfo
->CallbackHandle
= Handle
;
538 PackageList
= PreparePackages (1, &mStringPackGuid
, DriverSampleStrings
);
539 Status
= Hii
->NewPack (Hii
, PackageList
, &HiiHandle
);
540 gBS
->FreePool (PackageList
);
542 PackageList
= PreparePackages (1, &mStringPackGuid
, InventoryBin
);
543 Status
= Hii
->NewPack (Hii
, PackageList
, &HiiHandle
);
544 gBS
->FreePool (PackageList
);
546 PackageList
= PreparePackages (1, &mStringPackGuid
, VfrBin
);
547 Status
= Hii
->NewPack (Hii
, PackageList
, &HiiHandle
);
548 gBS
->FreePool (PackageList
);
550 CallbackInfo
->RegisteredHandle
= HiiHandle
;
553 // Very simple example of how one would update a string that is already
554 // in the HII database
556 TokenToUpdate
= (STRING_REF
) STR_CPU_STRING2
;
557 NewString
= (CHAR16
*) L
"700 Mhz";
559 Hii
->NewString (Hii
, NULL
, HiiHandle
, &TokenToUpdate
, NewString
);
562 // Add a string - if 0 will be updated with new Token number
564 TokenToUpdate
= (STRING_REF
) 0;
567 // Add a string - if 0 will be updated with new Token number
569 TokenToUpdate2
= (STRING_REF
) 0;
572 // Add a string - if 0 will be updated with new Token number
574 TokenToUpdate3
= (STRING_REF
) 0;
576 Hii
->NewString (Hii
, NULL
, HiiHandle
, &TokenToUpdate
, (CHAR16
*) L
"Desired Speed");
577 Hii
->NewString (Hii
, NULL
, HiiHandle
, &TokenToUpdate2
, (CHAR16
*) L
"5 Thz");
578 Hii
->NewString (Hii
, NULL
, HiiHandle
, &TokenToUpdate3
, (CHAR16
*) L
"This is next year's desired speed - right?");
581 // Allocate space for creation of Buffer
583 Status
= gBS
->AllocatePool (
586 (VOID
**) &UpdateData
589 ZeroMem (UpdateData
, 0x1000);
592 // Flag update pending in FormSet
594 UpdateData
->FormSetUpdate
= TRUE
;
596 // Register CallbackHandle data for FormSet
598 UpdateData
->FormCallbackHandle
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) CallbackInfo
->CallbackHandle
;
599 UpdateData
->FormUpdate
= FALSE
;
600 UpdateData
->FormTitle
= 0;
601 UpdateData
->DataCount
= 1;
603 CreateTextOpCode (TokenToUpdate
, TokenToUpdate2
, TokenToUpdate3
, 0, 0, &UpdateData
->Data
);
605 Hii
->UpdateForm (Hii
, HiiHandle
, (EFI_FORM_LABEL
) 100, TRUE
, UpdateData
);
607 gBS
->FreePool (UpdateData
);
610 // Example of how to display only the item we sent to HII
612 if (DISPLAY_ONLY_MY_ITEM
== 0x0001) {
614 // Have the browser pull out our copy of the data, and only display our data
616 // Status = FormConfig->SendForm (FormConfig, TRUE, HiiHandle, NULL, NULL, NULL, &Screen, NULL);
620 // Have the browser pull out all the data in the HII Database and display it.
622 // Status = FormConfig->SendForm (FormConfig, TRUE, 0, NULL, NULL, NULL, NULL, NULL);
626 if (EFI_ERROR (Status
)) {