audk/IntelFrameworkModulePkg/Universal/DriverSampleDxe/DriverSample.c

599 lines
19 KiB
C

/*++
Copyright (c) 2006 - 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
DriverSample.c
Abstract:
This is an example of how a driver might export data to the HII protocol to be
later utilized by the Setup Protocol
--*/
//
// Include common header file for this module.
//
#include "CommonHeader.h"
#include "DriverSample.h"
#define DISPLAY_ONLY_MY_ITEM 0x0001
#define STRING_PACK_GUID \
{ \
0x8160a85f, 0x934d, 0x468b, { 0xa2, 0x35, 0x72, 0x89, 0x59, 0x14, 0xf6, 0xfc } \
}
EFI_GUID mFormSetGuid = FORMSET_GUID;
EFI_GUID mStringPackGuid = STRING_PACK_GUID;
STATIC
EFI_STATUS
EFIAPI
DriverCallback (
IN EFI_FORM_CALLBACK_PROTOCOL *This,
IN UINT16 KeyValue,
IN EFI_IFR_DATA_ARRAY *Data,
OUT EFI_HII_CALLBACK_PACKET **Packet
)
/*++
Routine Description:
This is the function that is called to provide results data to the driver. This data
consists of a unique key which is used to identify what data is either being passed back
or being asked for.
Arguments:
KeyValue - A unique value which is sent to the original exporting driver so that it
can identify the type of data to expect. The format of the data tends to
vary based on the op-code that geerated the callback.
Data - A pointer to the data being sent to the original exporting driver.
Returns:
--*/
{
EFI_CALLBACK_INFO *Private;
EFI_HII_UPDATE_DATA *UpdateData;
UINT8 *Location;
EFI_HII_CALLBACK_PACKET *DataPacket;
UINT16 Value;
CHAR16 VariableName[40];
STATIC UINT16 QuestionId = 0;
IFR_OPTION *OptionList;
UINTN Index;
MyIfrNVData NVStruc;
Private = EFI_CALLBACK_INFO_FROM_THIS (This);
//
// This should tell me the first offset AFTER the end of the compiled NV map
// If op-code results are not going to be saved to NV locations ensure the QuestionId
// is beyond the end of the NVRAM mapping.
//
if (QuestionId == 0) {
QuestionId = sizeof (MyIfrNVData);
}
ZeroMem (VariableName, (sizeof (CHAR16) * 40));
switch (KeyValue) {
case 0x0001:
//
// Create a small boot order list
//
QuestionId = (UINT16) ((UINTN) (&NVStruc.BootOrder) - (UINTN) (&NVStruc));
//
// Need some memory for OptionList. Allow for up to 8 options.
//
OptionList = AllocateZeroPool (sizeof (IFR_OPTION) * 8);
ASSERT (OptionList != NULL);
//
// Allocate space for creation of Buffer
//
UpdateData = AllocateZeroPool (0x1000);
ASSERT (UpdateData != NULL);
//
// Remove all the op-codes starting with Label 0x2222 to next Label (second label is for convenience
// so we don't have to keep track of how many op-codes we added or subtracted. The rules for removal
// of op-codes are simply that the removal will always stop as soon as a label or the end of a form is
// encountered. Therefore, giving a large obnoxious count such as below takes care of other complexities.
//
UpdateData->DataCount = 0xFF;
//
// Delete set of op-codes
//
Private->Hii->UpdateForm (
Private->Hii,
Private->RegisteredHandle,
(EFI_FORM_LABEL) 0x2222,
FALSE, // If we aren't adding, we are deleting
UpdateData
);
//
// Create 3 options
//
for (Index = 0; Index < 3; Index++) {
OptionList[Index].StringToken = (UINT16) (STR_BOOT_OPTION1 + Index);
OptionList[Index].Value = (UINT16) (Index + 1);
OptionList[Index].Flags = RESET_REQUIRED;
}
CreateOrderedListOpCode (
QuestionId, // Question ID
8, // Max Entries
(UINT16) STRING_TOKEN (STR_BOOT_OPTIONS), // Token value for the Prompt
(UINT16) STRING_TOKEN (STR_NULL_STRING), // Token value for the Help
OptionList,
3,
&UpdateData->Data // Buffer location to place op-codes
);
//
// For one-of/ordered lists commands, they really consist of 2 op-codes (a header and a footer)
// Each option within a one-of/ordered list is also an op-code
// So this example has 5 op-codes it is adding since we have a one-of header + 3 options + one-of footer
//
UpdateData->DataCount = 0x5;
//
// Add one op-code
//
Private->Hii->UpdateForm (
Private->Hii,
Private->RegisteredHandle,
(EFI_FORM_LABEL) 0x2222,
TRUE,
UpdateData
);
FreePool (UpdateData);
FreePool (OptionList);
break;
case 0x0002:
//
// Create a large boot order list
//
QuestionId = (UINT16) ((UINTN) (&NVStruc.BootOrder) - (UINTN) (&NVStruc));
//
// Need some memory for OptionList. Allow for up to 8 options.
//
OptionList = AllocateZeroPool (sizeof (IFR_OPTION) * 8);
ASSERT (OptionList != NULL);
//
// Allocate space for creation of Buffer
//
UpdateData = AllocateZeroPool (0x1000);
ASSERT (UpdateData != NULL);
//
// Remove all the op-codes starting with Label 0x2222 to next Label (second label is for convenience
// so we don't have to keep track of how many op-codes we added or subtracted
//
UpdateData->DataCount = 0xFF;
//
// Delete one op-code
//
Private->Hii->UpdateForm (
Private->Hii,
Private->RegisteredHandle,
(EFI_FORM_LABEL) 0x2222,
FALSE,
UpdateData
);
//
// Create 4 options
//
for (Index = 0; Index < 4; Index++) {
OptionList[Index].StringToken = (UINT16) (STR_BOOT_OPTION1 + Index);
OptionList[Index].Value = (UINT16) (Index + 1);
OptionList[Index].Flags = RESET_REQUIRED;
}
CreateOrderedListOpCode (
QuestionId, // Question ID
8, // Max Entries
(UINT16) STRING_TOKEN (STR_BOOT_OPTIONS), // Token value for the Prompt
(UINT16) STRING_TOKEN (STR_NULL_STRING), // Token value for the Help
OptionList,
4,
&UpdateData->Data // Buffer location to place op-codes
);
//
// For one-of commands, they really consist of 2 op-codes (a header and a footer)
// Each option within a one-of is also an op-code
// So this example has 6 op-codes it is adding since we have a one-of header + 4 options + one-of footer
//
UpdateData->DataCount = 0x6;
//
// Add one op-code
//
Private->Hii->UpdateForm (
Private->Hii,
Private->RegisteredHandle,
(EFI_FORM_LABEL) 0x2222,
TRUE,
UpdateData
);
FreePool (UpdateData);
FreePool (OptionList);
break;
case 0x1234:
//
// Allocate space for creation of Buffer
//
QuestionId = (UINT16) ((UINTN) (&NVStruc.DynamicCheck) - (UINTN) (&NVStruc));
UpdateData = AllocateZeroPool (0x1000);
ASSERT (UpdateData != NULL);
Location = (UINT8 *) &UpdateData->Data;
UpdateData->FormSetUpdate = TRUE;
UpdateData->FormCallbackHandle = (EFI_PHYSICAL_ADDRESS) (UINTN) Private->CallbackHandle;
UpdateData->FormUpdate = FALSE;
UpdateData->FormTitle = 0;
UpdateData->DataCount = 2;
CreateGotoOpCode (
1,
STR_GOTO_FORM1, // Token value for the Prompt
0, // Goto Help
0, // Flags
0, // Key
&UpdateData->Data // Buffer location to place op-codes
);
Location = Location + ((EFI_IFR_OP_HEADER *) &UpdateData->Data)->Length;
CreateCheckBoxOpCode (
QuestionId, // Question ID
1, // Data width (BOOLEAN = 1)
(UINT16) STRING_TOKEN (STR_CHECK_DYNAMIC_PROMPT), // Token value for the Prompt
(UINT16) STRING_TOKEN (STR_CHECK_DYNAMIC_HELP), // Token value for the Help
EFI_IFR_FLAG_INTERACTIVE, // Flags
0x1236, // Key
Location // Buffer location to place op-codes
);
Private->Hii->UpdateForm (
Private->Hii,
Private->RegisteredHandle,
(EFI_FORM_LABEL) 0x1234,
TRUE,
UpdateData
);
FreePool (UpdateData);
QuestionId++;
break;
case 0x1235:
//
// Allocate space for creation of Buffer
//
UpdateData = AllocateZeroPool (0x1000);
ASSERT (UpdateData != NULL);
//
// Initialize DataPacket with information intended to remove all
// previously created op-codes in the dynamic page
//
UpdateData->FormSetUpdate = FALSE;
UpdateData->FormCallbackHandle = 0;
UpdateData->FormUpdate = FALSE;
UpdateData->FormTitle = 0;
//
// Unlikely to be more than 0xff op-codes in the dynamic page to remove
//
UpdateData->DataCount = 0xff;
UpdateData->Data = NULL;
//
// Remove all op-codes from dynamic page
//
Private->Hii->UpdateForm (
Private->Hii,
Private->RegisteredHandle,
(EFI_FORM_LABEL) 0x1234, // Label 0x1234
FALSE, // Remove Op-codes (will never remove form/endform)
UpdateData // Significant value is UpdateData->DataCount
);
UpdateData->FormSetUpdate = FALSE;
UpdateData->FormCallbackHandle = 0;
UpdateData->FormUpdate = FALSE;
UpdateData->FormTitle = 0;
UpdateData->DataCount = 1;
CreateGotoOpCode (
1,
STR_GOTO_FORM1, // Token value for the Prompt
0, // Goto Help
0, // Flags
0, // Key
&UpdateData->Data // Buffer location to place op-codes
);
Private->Hii->UpdateForm (
Private->Hii,
Private->RegisteredHandle,
(EFI_FORM_LABEL) 0x1234,
TRUE,
UpdateData
);
FreePool (UpdateData);
break;
case 0x1236:
//
// If I hit the checkbox, I enter this case statement...
//
//
// Since I am returning an error (for test purposes) I need to pass in the string for the error
// I will allocate space for the return value. If an error occurs (which is the case) I can simply return
// an error and fill in the string parameter, otherwise, I will return information in the DataArray structure.
// The browser will free this packet structure
//
*Packet = AllocateZeroPool (sizeof (EFI_HII_CALLBACK_PACKET) + sizeof (SAMPLE_STRING) + 2);
ASSERT (*Packet != NULL);
//
// Assign the buffer address to DataPacket
//
DataPacket = *Packet;
StrCpy (DataPacket->String, (CHAR16 *) SAMPLE_STRING);
return EFI_DEVICE_ERROR;
case 0x1237:
*Packet = AllocateZeroPool (sizeof (EFI_HII_CALLBACK_PACKET) + 2);
ASSERT (*Packet != NULL);
//
// Assign the buffer address to DataPacket
//
DataPacket = *Packet;
DataPacket->DataArray.EntryCount = 1;
DataPacket->DataArray.NvRamMap = NULL;
((EFI_IFR_DATA_ENTRY *) (&DataPacket->DataArray + 1))->Flags = EXIT_REQUIRED;
break;
case 0x1555:
Value = 0x0001;
UnicodeSPrint (VariableName, 0x80, (CHAR16 *) L"%d", VAR_EQ_TEST_NAME);
gRT->SetVariable (
VariableName,
&mFormSetGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
2,
(VOID *) &Value
);
break;
case 0x1556:
Value = 0x1000;
UnicodeSPrint (VariableName, 0x80, (CHAR16 *) L"%d", VAR_EQ_TEST_NAME);
gRT->SetVariable (
VariableName,
&mFormSetGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
2,
(VOID *) &Value
);
break;
case 0x1557:
Value = 0x0000;
UnicodeSPrint (VariableName, 0x80, (CHAR16 *) L"%d", VAR_EQ_TEST_NAME);
gRT->SetVariable (
VariableName,
&mFormSetGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
2,
(VOID *) &Value
);
break;
default:
break;
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
DriverSampleInit (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_HII_PROTOCOL *Hii;
//
// EFI_FORM_BROWSER_PROTOCOL *FormConfig;
//
EFI_HII_PACKAGES *PackageList;
EFI_HII_HANDLE HiiHandle;
STRING_REF TokenToUpdate;
STRING_REF TokenToUpdate2;
STRING_REF TokenToUpdate3;
CHAR16 *NewString;
EFI_HII_UPDATE_DATA *UpdateData;
EFI_CALLBACK_INFO *CallbackInfo;
EFI_HANDLE Handle;
EFI_SCREEN_DESCRIPTOR Screen;
ZeroMem (&Screen, sizeof (EFI_SCREEN_DESCRIPTOR));
gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Screen.RightColumn, &Screen.BottomRow);
//
// Remove 3 characters from top and bottom
//
Screen.TopRow = 3;
Screen.BottomRow = Screen.BottomRow - 3;
//
// There should only be one HII protocol
//
Status = gBS->LocateProtocol (
&gEfiHiiProtocolGuid,
NULL,
(VOID **) &Hii
);
if (EFI_ERROR (Status)) {
return Status;;
}
CallbackInfo = AllocatePool (sizeof (EFI_CALLBACK_INFO));
if (CallbackInfo == NULL) {
return EFI_OUT_OF_RESOURCES;
}
CallbackInfo->Signature = EFI_CALLBACK_INFO_SIGNATURE;
CallbackInfo->Hii = Hii;
//
// This example does not implement worker functions for the NV accessor functions. Only a callback evaluator
//
CallbackInfo->DriverCallback.NvRead = NULL;
CallbackInfo->DriverCallback.NvWrite = NULL;
CallbackInfo->DriverCallback.Callback = DriverCallback;
//
// Install protocol interface
//
Handle = NULL;
Status = gBS->InstallProtocolInterface (
&Handle,
&gEfiFormCallbackProtocolGuid,
EFI_NATIVE_INTERFACE,
&CallbackInfo->DriverCallback
);
ASSERT_EFI_ERROR (Status);
CallbackInfo->CallbackHandle = Handle;
PackageList = PreparePackages (1, &mStringPackGuid, DriverSampleStrings);
Status = Hii->NewPack (Hii, PackageList, &HiiHandle);
FreePool (PackageList);
PackageList = PreparePackages (1, &mStringPackGuid, InventoryBin);
Status = Hii->NewPack (Hii, PackageList, &HiiHandle);
FreePool (PackageList);
PackageList = PreparePackages (1, &mStringPackGuid, VfrBin);
Status = Hii->NewPack (Hii, PackageList, &HiiHandle);
FreePool (PackageList);
CallbackInfo->RegisteredHandle = HiiHandle;
//
// Very simple example of how one would update a string that is already
// in the HII database
//
TokenToUpdate = (STRING_REF) STR_CPU_STRING2;
NewString = (CHAR16 *) L"700 Mhz";
Hii->NewString (Hii, NULL, HiiHandle, &TokenToUpdate, NewString);
//
// Add a string - if 0 will be updated with new Token number
//
TokenToUpdate = (STRING_REF) 0;
//
// Add a string - if 0 will be updated with new Token number
//
TokenToUpdate2 = (STRING_REF) 0;
//
// Add a string - if 0 will be updated with new Token number
//
TokenToUpdate3 = (STRING_REF) 0;
Hii->NewString (Hii, NULL, HiiHandle, &TokenToUpdate, (CHAR16 *) L"Desired Speed");
Hii->NewString (Hii, NULL, HiiHandle, &TokenToUpdate2, (CHAR16 *) L"5 Thz");
Hii->NewString (Hii, NULL, HiiHandle, &TokenToUpdate3, (CHAR16 *) L"This is next year's desired speed - right?");
//
// Allocate space for creation of Buffer
//
UpdateData = AllocateZeroPool (0x1000);
ASSERT (UpdateData != NULL);
//
// Flag update pending in FormSet
//
UpdateData->FormSetUpdate = TRUE;
//
// Register CallbackHandle data for FormSet
//
UpdateData->FormCallbackHandle = (EFI_PHYSICAL_ADDRESS) (UINTN) CallbackInfo->CallbackHandle;
UpdateData->FormUpdate = FALSE;
UpdateData->FormTitle = 0;
UpdateData->DataCount = 1;
CreateTextOpCode (TokenToUpdate, TokenToUpdate2, TokenToUpdate3, 0, 0, &UpdateData->Data);
Hii->UpdateForm (Hii, HiiHandle, (EFI_FORM_LABEL) 100, TRUE, UpdateData);
FreePool (UpdateData);
//
// Example of how to display only the item we sent to HII
//
if (DISPLAY_ONLY_MY_ITEM == 0x0001) {
//
// Have the browser pull out our copy of the data, and only display our data
//
// Status = FormConfig->SendForm (FormConfig, TRUE, HiiHandle, NULL, NULL, NULL, &Screen, NULL);
//
} else {
//
// Have the browser pull out all the data in the HII Database and display it.
//
// Status = FormConfig->SendForm (FormConfig, TRUE, 0, NULL, NULL, NULL, NULL, NULL);
//
}
if (EFI_ERROR (Status)) {
return Status;
}
return EFI_SUCCESS;
}