2 Copyright (c) 2006 - 2007, 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
;
37 IN EFI_FORM_CALLBACK_PROTOCOL
*This
,
39 IN EFI_IFR_DATA_ARRAY
*Data
,
40 OUT EFI_HII_CALLBACK_PACKET
**Packet
46 This is the function that is called to provide results data to the driver. This data
47 consists of a unique key which is used to identify what data is either being passed back
52 KeyValue - A unique value which is sent to the original exporting driver so that it
53 can identify the type of data to expect. The format of the data tends to
54 vary based on the op-code that geerated the callback.
56 Data - A pointer to the data being sent to the original exporting driver.
62 EFI_CALLBACK_INFO
*Private
;
63 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);
97 ASSERT (OptionList
!= NULL
);
100 // Allocate space for creation of Buffer
102 UpdateData
= AllocateZeroPool (0x1000);
103 ASSERT (UpdateData
!= NULL
);
106 // Remove all the op-codes starting with Label 0x2222 to next Label (second label is for convenience
107 // so we don't have to keep track of how many op-codes we added or subtracted. The rules for removal
108 // of op-codes are simply that the removal will always stop as soon as a label or the end of a form is
109 // encountered. Therefore, giving a large obnoxious count such as below takes care of other complexities.
111 UpdateData
->DataCount
= 0xFF;
114 // Delete set of op-codes
116 Private
->Hii
->UpdateForm (
118 Private
->RegisteredHandle
,
119 (EFI_FORM_LABEL
) 0x2222,
120 FALSE
, // If we aren't adding, we are deleting
127 for (Index
= 0; Index
< 3; Index
++) {
128 OptionList
[Index
].StringToken
= (UINT16
) (STR_BOOT_OPTION1
+ Index
);
129 OptionList
[Index
].Value
= (UINT16
) (Index
+ 1);
130 OptionList
[Index
].Flags
= RESET_REQUIRED
;
133 CreateOrderedListOpCode (
134 QuestionId
, // Question ID
136 (UINT16
) STRING_TOKEN (STR_BOOT_OPTIONS
), // Token value for the Prompt
137 (UINT16
) STRING_TOKEN (STR_NULL_STRING
), // Token value for the Help
140 &UpdateData
->Data
// Buffer location to place op-codes
144 // For one-of/ordered lists commands, they really consist of 2 op-codes (a header and a footer)
145 // Each option within a one-of/ordered list is also an op-code
146 // So this example has 5 op-codes it is adding since we have a one-of header + 3 options + one-of footer
148 UpdateData
->DataCount
= 0x5;
153 Private
->Hii
->UpdateForm (
155 Private
->RegisteredHandle
,
156 (EFI_FORM_LABEL
) 0x2222,
161 FreePool (UpdateData
);
162 FreePool (OptionList
);
167 // Create a large boot order list
169 QuestionId
= (UINT16
) ((UINTN
) (&NVStruc
.BootOrder
) - (UINTN
) (&NVStruc
));
172 // Need some memory for OptionList. Allow for up to 8 options.
174 OptionList
= AllocateZeroPool (sizeof (IFR_OPTION
) * 8);
175 ASSERT (OptionList
!= NULL
);
178 // Allocate space for creation of Buffer
180 UpdateData
= AllocateZeroPool (0x1000);
181 ASSERT (UpdateData
!= NULL
);
184 // Remove all the op-codes starting with Label 0x2222 to next Label (second label is for convenience
185 // so we don't have to keep track of how many op-codes we added or subtracted
187 UpdateData
->DataCount
= 0xFF;
190 // Delete one op-code
192 Private
->Hii
->UpdateForm (
194 Private
->RegisteredHandle
,
195 (EFI_FORM_LABEL
) 0x2222,
203 for (Index
= 0; Index
< 4; Index
++) {
204 OptionList
[Index
].StringToken
= (UINT16
) (STR_BOOT_OPTION1
+ Index
);
205 OptionList
[Index
].Value
= (UINT16
) (Index
+ 1);
206 OptionList
[Index
].Flags
= RESET_REQUIRED
;
209 CreateOrderedListOpCode (
210 QuestionId
, // Question ID
212 (UINT16
) STRING_TOKEN (STR_BOOT_OPTIONS
), // Token value for the Prompt
213 (UINT16
) STRING_TOKEN (STR_NULL_STRING
), // Token value for the Help
216 &UpdateData
->Data
// Buffer location to place op-codes
220 // For one-of commands, they really consist of 2 op-codes (a header and a footer)
221 // Each option within a one-of is also an op-code
222 // So this example has 6 op-codes it is adding since we have a one-of header + 4 options + one-of footer
224 UpdateData
->DataCount
= 0x6;
229 Private
->Hii
->UpdateForm (
231 Private
->RegisteredHandle
,
232 (EFI_FORM_LABEL
) 0x2222,
237 FreePool (UpdateData
);
238 FreePool (OptionList
);
243 // Allocate space for creation of Buffer
245 QuestionId
= (UINT16
) ((UINTN
) (&NVStruc
.DynamicCheck
) - (UINTN
) (&NVStruc
));
246 UpdateData
= AllocateZeroPool (0x1000);
247 ASSERT (UpdateData
!= NULL
);
249 Location
= (UINT8
*) &UpdateData
->Data
;
251 UpdateData
->FormSetUpdate
= TRUE
;
252 UpdateData
->FormCallbackHandle
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) Private
->CallbackHandle
;
253 UpdateData
->FormUpdate
= FALSE
;
254 UpdateData
->FormTitle
= 0;
255 UpdateData
->DataCount
= 2;
259 STR_GOTO_FORM1
, // Token value for the Prompt
263 &UpdateData
->Data
// Buffer location to place op-codes
266 Location
= Location
+ ((EFI_IFR_OP_HEADER
*) &UpdateData
->Data
)->Length
;
268 CreateCheckBoxOpCode (
269 QuestionId
, // Question ID
270 1, // Data width (BOOLEAN = 1)
271 (UINT16
) STRING_TOKEN (STR_CHECK_DYNAMIC_PROMPT
), // Token value for the Prompt
272 (UINT16
) STRING_TOKEN (STR_CHECK_DYNAMIC_HELP
), // Token value for the Help
273 EFI_IFR_FLAG_INTERACTIVE
, // Flags
275 Location
// Buffer location to place op-codes
278 Private
->Hii
->UpdateForm (
280 Private
->RegisteredHandle
,
281 (EFI_FORM_LABEL
) 0x1234,
286 FreePool (UpdateData
);
292 // Allocate space for creation of Buffer
294 UpdateData
= AllocateZeroPool (0x1000);
295 ASSERT (UpdateData
!= NULL
);
298 // Initialize DataPacket with information intended to remove all
299 // previously created op-codes in the dynamic page
301 UpdateData
->FormSetUpdate
= FALSE
;
302 UpdateData
->FormCallbackHandle
= 0;
303 UpdateData
->FormUpdate
= FALSE
;
304 UpdateData
->FormTitle
= 0;
306 // Unlikely to be more than 0xff op-codes in the dynamic page to remove
308 UpdateData
->DataCount
= 0xff;
309 UpdateData
->Data
= NULL
;
312 // Remove all op-codes from dynamic page
314 Private
->Hii
->UpdateForm (
316 Private
->RegisteredHandle
,
317 (EFI_FORM_LABEL
) 0x1234, // Label 0x1234
318 FALSE
, // Remove Op-codes (will never remove form/endform)
319 UpdateData
// Significant value is UpdateData->DataCount
322 UpdateData
->FormSetUpdate
= FALSE
;
323 UpdateData
->FormCallbackHandle
= 0;
324 UpdateData
->FormUpdate
= FALSE
;
325 UpdateData
->FormTitle
= 0;
326 UpdateData
->DataCount
= 1;
330 STR_GOTO_FORM1
, // Token value for the Prompt
334 &UpdateData
->Data
// Buffer location to place op-codes
337 Private
->Hii
->UpdateForm (
339 Private
->RegisteredHandle
,
340 (EFI_FORM_LABEL
) 0x1234,
345 FreePool (UpdateData
);
350 // If I hit the checkbox, I enter this case statement...
353 // Since I am returning an error (for test purposes) I need to pass in the string for the error
354 // I will allocate space for the return value. If an error occurs (which is the case) I can simply return
355 // an error and fill in the string parameter, otherwise, I will return information in the DataArray structure.
356 // The browser will free this packet structure
358 *Packet
= AllocateZeroPool (sizeof (EFI_HII_CALLBACK_PACKET
) + sizeof (SAMPLE_STRING
) + 2);
359 ASSERT (*Packet
!= NULL
);
362 // Assign the buffer address to DataPacket
364 DataPacket
= *Packet
;
366 StrCpy (DataPacket
->String
, (CHAR16
*) SAMPLE_STRING
);
367 return EFI_DEVICE_ERROR
;
371 *Packet
= AllocateZeroPool (sizeof (EFI_HII_CALLBACK_PACKET
) + 2);
372 ASSERT (*Packet
!= NULL
);
375 // Assign the buffer address to DataPacket
377 DataPacket
= *Packet
;
379 DataPacket
->DataArray
.EntryCount
= 1;
380 DataPacket
->DataArray
.NvRamMap
= NULL
;
381 ((EFI_IFR_DATA_ENTRY
*) (&DataPacket
->DataArray
+ 1))->Flags
= EXIT_REQUIRED
;
386 UnicodeSPrint (VariableName
, 0x80, (CHAR16
*) L
"%d", VAR_EQ_TEST_NAME
);
391 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
399 UnicodeSPrint (VariableName
, 0x80, (CHAR16
*) L
"%d", VAR_EQ_TEST_NAME
);
404 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
412 UnicodeSPrint (VariableName
, 0x80, (CHAR16
*) L
"%d", VAR_EQ_TEST_NAME
);
417 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
433 IN EFI_HANDLE ImageHandle
,
434 IN EFI_SYSTEM_TABLE
*SystemTable
438 EFI_HII_PROTOCOL
*Hii
;
440 // EFI_FORM_BROWSER_PROTOCOL *FormConfig;
442 EFI_HII_PACKAGES
*PackageList
;
443 EFI_HII_HANDLE HiiHandle
;
444 STRING_REF TokenToUpdate
;
445 STRING_REF TokenToUpdate2
;
446 STRING_REF TokenToUpdate3
;
448 EFI_HII_UPDATE_DATA
*UpdateData
;
449 EFI_CALLBACK_INFO
*CallbackInfo
;
451 EFI_SCREEN_DESCRIPTOR Screen
;
453 ZeroMem (&Screen
, sizeof (EFI_SCREEN_DESCRIPTOR
));
455 gST
->ConOut
->QueryMode (gST
->ConOut
, gST
->ConOut
->Mode
->Mode
, &Screen
.RightColumn
, &Screen
.BottomRow
);
458 // Remove 3 characters from top and bottom
461 Screen
.BottomRow
= Screen
.BottomRow
- 3;
464 // There should only be one HII protocol
466 Status
= gBS
->LocateProtocol (
467 &gEfiHiiProtocolGuid
,
471 if (EFI_ERROR (Status
)) {
475 CallbackInfo
= AllocatePool (sizeof (EFI_CALLBACK_INFO
));
476 if (CallbackInfo
== NULL
) {
477 return EFI_OUT_OF_RESOURCES
;
480 CallbackInfo
->Signature
= EFI_CALLBACK_INFO_SIGNATURE
;
481 CallbackInfo
->Hii
= Hii
;
484 // This example does not implement worker functions for the NV accessor functions. Only a callback evaluator
486 CallbackInfo
->DriverCallback
.NvRead
= NULL
;
487 CallbackInfo
->DriverCallback
.NvWrite
= NULL
;
488 CallbackInfo
->DriverCallback
.Callback
= DriverCallback
;
491 // Install protocol interface
494 Status
= gBS
->InstallProtocolInterface (
496 &gEfiFormCallbackProtocolGuid
,
497 EFI_NATIVE_INTERFACE
,
498 &CallbackInfo
->DriverCallback
501 ASSERT_EFI_ERROR (Status
);
503 CallbackInfo
->CallbackHandle
= Handle
;
505 PackageList
= PreparePackages (1, &mStringPackGuid
, DriverSampleDxeStrings
);
506 Status
= Hii
->NewPack (Hii
, PackageList
, &HiiHandle
);
507 FreePool (PackageList
);
509 PackageList
= PreparePackages (1, &mStringPackGuid
, InventoryBin
);
510 Status
= Hii
->NewPack (Hii
, PackageList
, &HiiHandle
);
511 FreePool (PackageList
);
513 PackageList
= PreparePackages (1, &mStringPackGuid
, VfrBin
);
514 Status
= Hii
->NewPack (Hii
, PackageList
, &HiiHandle
);
515 FreePool (PackageList
);
517 CallbackInfo
->RegisteredHandle
= HiiHandle
;
520 // Very simple example of how one would update a string that is already
521 // in the HII database
523 TokenToUpdate
= (STRING_REF
) STR_CPU_STRING2
;
524 NewString
= (CHAR16
*) L
"700 Mhz";
526 Hii
->NewString (Hii
, NULL
, HiiHandle
, &TokenToUpdate
, NewString
);
529 // Add a string - if 0 will be updated with new Token number
531 TokenToUpdate
= (STRING_REF
) 0;
534 // Add a string - if 0 will be updated with new Token number
536 TokenToUpdate2
= (STRING_REF
) 0;
539 // Add a string - if 0 will be updated with new Token number
541 TokenToUpdate3
= (STRING_REF
) 0;
543 Hii
->NewString (Hii
, NULL
, HiiHandle
, &TokenToUpdate
, (CHAR16
*) L
"Desired Speed");
544 Hii
->NewString (Hii
, NULL
, HiiHandle
, &TokenToUpdate2
, (CHAR16
*) L
"5 Thz");
545 Hii
->NewString (Hii
, NULL
, HiiHandle
, &TokenToUpdate3
, (CHAR16
*) L
"This is next year's desired speed - right?");
548 // Allocate space for creation of Buffer
550 UpdateData
= AllocateZeroPool (0x1000);
551 ASSERT (UpdateData
!= NULL
);
554 // Flag update pending in FormSet
556 UpdateData
->FormSetUpdate
= TRUE
;
558 // Register CallbackHandle data for FormSet
560 UpdateData
->FormCallbackHandle
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) CallbackInfo
->CallbackHandle
;
561 UpdateData
->FormUpdate
= FALSE
;
562 UpdateData
->FormTitle
= 0;
563 UpdateData
->DataCount
= 1;
565 CreateTextOpCode (TokenToUpdate
, TokenToUpdate2
, TokenToUpdate3
, 0, 0, &UpdateData
->Data
);
567 Hii
->UpdateForm (Hii
, HiiHandle
, (EFI_FORM_LABEL
) 100, TRUE
, UpdateData
);
569 FreePool (UpdateData
);
572 // Example of how to display only the item we sent to HII
574 if (DISPLAY_ONLY_MY_ITEM
== 0x0001) {
576 // Have the browser pull out our copy of the data, and only display our data
578 // Status = FormConfig->SendForm (FormConfig, TRUE, HiiHandle, NULL, NULL, NULL, &Screen, NULL);
582 // Have the browser pull out all the data in the HII Database and display it.
584 // Status = FormConfig->SendForm (FormConfig, TRUE, 0, NULL, NULL, NULL, NULL, NULL);
588 if (EFI_ERROR (Status
)) {