/** @file This is an example of how a driver might export data to the HII protocol to be later utilized by the Setup Protocol Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "DriverSample.h" #define DISPLAY_ONLY_MY_ITEM 0x0002 CHAR16 VariableName[] = L"MyIfrNVData"; CHAR16 MyEfiVar[] = L"MyEfiVar"; CHAR16 MyEfiBitVar[] = L"MyEfiBitVar"; CHAR16 MyEfiUnionVar[] = L"MyEfiUnionVar"; EFI_HANDLE DriverHandle[2] = {NULL, NULL}; DRIVER_SAMPLE_PRIVATE_DATA *mPrivateData = NULL; EFI_EVENT mEvent; HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath0 = { { { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { (UINT8) (sizeof (VENDOR_DEVICE_PATH)), (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) } }, DRIVER_SAMPLE_FORMSET_GUID }, { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { (UINT8) (END_DEVICE_PATH_LENGTH), (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) } } }; HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath1 = { { { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { (UINT8) (sizeof (VENDOR_DEVICE_PATH)), (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) } }, DRIVER_SAMPLE_INVENTORY_GUID }, { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { (UINT8) (END_DEVICE_PATH_LENGTH), (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) } } }; /** Set value of a data element in an Array by its Index. @param Array The data array. @param Type Type of the data in this array. @param Index Zero based index for data in this array. @param Value The value to be set. **/ VOID SetArrayData ( IN VOID *Array, IN UINT8 Type, IN UINTN Index, IN UINT64 Value ) { ASSERT (Array != NULL); switch (Type) { case EFI_IFR_TYPE_NUM_SIZE_8: *(((UINT8 *) Array) + Index) = (UINT8) Value; break; case EFI_IFR_TYPE_NUM_SIZE_16: *(((UINT16 *) Array) + Index) = (UINT16) Value; break; case EFI_IFR_TYPE_NUM_SIZE_32: *(((UINT32 *) Array) + Index) = (UINT32) Value; break; case EFI_IFR_TYPE_NUM_SIZE_64: *(((UINT64 *) Array) + Index) = (UINT64) Value; break; default: break; } } /** Notification function for keystrokes. @param[in] KeyData The key that was pressed. @retval EFI_SUCCESS The operation was successful. **/ EFI_STATUS EFIAPI NotificationFunction( IN EFI_KEY_DATA *KeyData ) { gBS->SignalEvent (mEvent); return EFI_SUCCESS; } /** Function to start monitoring for CTRL-C using SimpleTextInputEx. @retval EFI_SUCCESS The feature is enabled. @retval EFI_OUT_OF_RESOURCES There is not enough mnemory available. **/ EFI_STATUS EFIAPI InternalStartMonitor( VOID ) { EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx; EFI_KEY_DATA KeyData; EFI_STATUS Status; EFI_HANDLE *Handles; UINTN HandleCount; UINTN HandleIndex; VOID *NotifyHandle; Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiSimpleTextInputExProtocolGuid, NULL, &HandleCount, &Handles ); for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { Status = gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &SimpleEx); ASSERT_EFI_ERROR (Status); KeyData.KeyState.KeyToggleState = 0; KeyData.Key.ScanCode = 0; KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED; KeyData.Key.UnicodeChar = L'c'; Status = SimpleEx->RegisterKeyNotify( SimpleEx, &KeyData, NotificationFunction, &NotifyHandle); if (EFI_ERROR (Status)) { break; } KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED; Status = SimpleEx->RegisterKeyNotify( SimpleEx, &KeyData, NotificationFunction, &NotifyHandle); if (EFI_ERROR (Status)) { break; } } return EFI_SUCCESS; } /** Function to stop monitoring for CTRL-C using SimpleTextInputEx. @retval EFI_SUCCESS The feature is enabled. @retval EFI_OUT_OF_RESOURCES There is not enough mnemory available. **/ EFI_STATUS EFIAPI InternalStopMonitor( VOID ) { EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx; EFI_STATUS Status; EFI_HANDLE *Handles; EFI_KEY_DATA KeyData; UINTN HandleCount; UINTN HandleIndex; VOID *NotifyHandle; Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiSimpleTextInputExProtocolGuid, NULL, &HandleCount, &Handles ); for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { Status = gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &SimpleEx); ASSERT_EFI_ERROR (Status); KeyData.KeyState.KeyToggleState = 0; KeyData.Key.ScanCode = 0; KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED; KeyData.Key.UnicodeChar = L'c'; Status = SimpleEx->RegisterKeyNotify( SimpleEx, &KeyData, NotificationFunction, &NotifyHandle); if (!EFI_ERROR (Status)) { Status = SimpleEx->UnregisterKeyNotify (SimpleEx, NotifyHandle); } KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED; Status = SimpleEx->RegisterKeyNotify( SimpleEx, &KeyData, NotificationFunction, &NotifyHandle); if (!EFI_ERROR (Status)) { Status = SimpleEx->UnregisterKeyNotify (SimpleEx, NotifyHandle); } } return EFI_SUCCESS; } /** Update names of Name/Value storage to current language. @param PrivateData Points to the driver private data. @retval EFI_SUCCESS All names are successfully updated. @retval EFI_NOT_FOUND Failed to get Name from HII database. **/ EFI_STATUS LoadNameValueNames ( IN DRIVER_SAMPLE_PRIVATE_DATA *PrivateData ) { UINTN Index; // // Get Name/Value name string of current language // for (Index = 0; Index < NAME_VALUE_NAME_NUMBER; Index++) { PrivateData->NameValueName[Index] = HiiGetString ( PrivateData->HiiHandle[0], PrivateData->NameStringId[Index], NULL ); if (PrivateData->NameValueName[Index] == NULL) { return EFI_NOT_FOUND; } } return EFI_SUCCESS; } /** Get the value of in format, i.e. the value of OFFSET or WIDTH or VALUE. ::= 'OFFSET='&'WIDTH='&'VALUE'= This is a internal function. @param StringPtr String in format and points to the first character of . @param Number The output value. Caller takes the responsibility to free memory. @param Len Length of the , in characters. @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary structures. @retval EFI_SUCCESS Value of is outputted in Number successfully. **/ EFI_STATUS GetValueOfNumber ( IN EFI_STRING StringPtr, OUT UINT8 **Number, OUT UINTN *Len ) { EFI_STRING TmpPtr; UINTN Length; EFI_STRING Str; UINT8 *Buf; EFI_STATUS Status; UINT8 DigitUint8; UINTN Index; CHAR16 TemStr[2]; if (StringPtr == NULL || *StringPtr == L'\0' || Number == NULL || Len == NULL) { return EFI_INVALID_PARAMETER; } Buf = NULL; TmpPtr = StringPtr; while (*StringPtr != L'\0' && *StringPtr != L'&') { StringPtr++; } *Len = StringPtr - TmpPtr; Length = *Len + 1; Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16)); if (Str == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Exit; } CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16)); *(Str + *Len) = L'\0'; Length = (Length + 1) / 2; Buf = (UINT8 *) AllocateZeroPool (Length); if (Buf == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Exit; } Length = *Len; ZeroMem (TemStr, sizeof (TemStr)); for (Index = 0; Index < Length; Index ++) { TemStr[0] = Str[Length - Index - 1]; DigitUint8 = (UINT8) StrHexToUint64 (TemStr); if ((Index & 1) == 0) { Buf [Index/2] = DigitUint8; } else { Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]); } } *Number = Buf; Status = EFI_SUCCESS; Exit: if (Str != NULL) { FreePool (Str); } return Status; } /** Create altcfg string. @param Result The request result string. @param ConfigHdr The request head info. format. @param Offset The offset of the parameter int he structure. @param Width The width of the parameter. @retval The string with altcfg info append at the end. **/ EFI_STRING CreateAltCfgString ( IN EFI_STRING Result, IN EFI_STRING ConfigHdr, IN UINTN Offset, IN UINTN Width ) { EFI_STRING StringPtr; EFI_STRING TmpStr; UINTN NewLen; NewLen = StrLen (Result); // // String Len = ConfigResp + AltConfig + AltConfig + 1("\0") // NewLen = (NewLen + ((1 + StrLen (ConfigHdr) + 8 + 4) + (8 + 4 + 7 + 4 + 7 + 4)) * 2 + 1) * sizeof (CHAR16); StringPtr = AllocateZeroPool (NewLen); if (StringPtr == NULL) { return NULL; } TmpStr = StringPtr; if (Result != NULL) { StrCpyS (StringPtr, NewLen / sizeof (CHAR16), Result); StringPtr += StrLen (Result); FreePool (Result); } UnicodeSPrint ( StringPtr, (1 + StrLen (ConfigHdr) + 8 + 4 + 1) * sizeof (CHAR16), L"&%s&ALTCFG=%04x", ConfigHdr, EFI_HII_DEFAULT_CLASS_STANDARD ); StringPtr += StrLen (StringPtr); UnicodeSPrint ( StringPtr, (8 + 4 + 7 + 4 + 7 + 4 + 1) * sizeof (CHAR16), L"&OFFSET=%04x&WIDTH=%04x&VALUE=%04x", Offset, Width, DEFAULT_CLASS_STANDARD_VALUE ); StringPtr += StrLen (StringPtr); UnicodeSPrint ( StringPtr, (1 + StrLen (ConfigHdr) + 8 + 4 + 1) * sizeof (CHAR16), L"&%s&ALTCFG=%04x", ConfigHdr, EFI_HII_DEFAULT_CLASS_MANUFACTURING ); StringPtr += StrLen (StringPtr); UnicodeSPrint ( StringPtr, (8 + 4 + 7 + 4 + 7 + 4 + 1) * sizeof (CHAR16), L"&OFFSET=%04x&WIDTH=%04x&VALUE=%04x", Offset, Width, DEFAULT_CLASS_MANUFACTURING_VALUE ); StringPtr += StrLen (StringPtr); return TmpStr; } /** Check whether need to add the altcfg string. if need to add, add the altcfg string. @param RequestResult The request result string. @param ConfigRequestHdr The request head info. format. **/ VOID AppendAltCfgString ( IN OUT EFI_STRING *RequestResult, IN EFI_STRING ConfigRequestHdr ) { EFI_STRING StringPtr; UINTN Length; UINT8 *TmpBuffer; UINTN Offset; UINTN Width; UINTN BlockSize; UINTN ValueOffset; UINTN ValueWidth; EFI_STATUS Status; TmpBuffer = NULL; StringPtr = *RequestResult; StringPtr = StrStr (StringPtr, L"OFFSET"); BlockSize = sizeof (DRIVER_SAMPLE_CONFIGURATION); ValueOffset = OFFSET_OF (DRIVER_SAMPLE_CONFIGURATION, GetDefaultValueFromAccess); ValueWidth = sizeof (((DRIVER_SAMPLE_CONFIGURATION *)0)->GetDefaultValueFromAccess); if (StringPtr == NULL) { return; } while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) { StringPtr += StrLen (L"OFFSET="); // // Get Offset // Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length); if (EFI_ERROR (Status)) { return; } Offset = 0; CopyMem ( &Offset, TmpBuffer, (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN) ); FreePool (TmpBuffer); StringPtr += Length; if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) { return; } StringPtr += StrLen (L"&WIDTH="); // // Get Width // Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length); if (EFI_ERROR (Status)) { return; } Width = 0; CopyMem ( &Width, TmpBuffer, (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN) ); FreePool (TmpBuffer); StringPtr += Length; if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) { return; } StringPtr += StrLen (L"&VALUE="); // // Get Value // Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length); if (EFI_ERROR (Status)) { return; } StringPtr += Length; // // Skip the character "&" before "OFFSET". // StringPtr ++; // // Calculate Value and convert it to hex string. // if (Offset + Width > BlockSize) { return; } if (Offset <= ValueOffset && Offset + Width >= ValueOffset + ValueWidth) { *RequestResult = CreateAltCfgString(*RequestResult, ConfigRequestHdr, ValueOffset, ValueWidth); return; } } } /** This function allows a caller to extract the current configuration for one or more named elements from the target driver. @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param Request A null-terminated Unicode string in format. @param Progress On return, points to a character in the Request string. Points to the string's null terminator if request was successful. Points to the most recent '&' before the first failing name/value pair (or the beginning of the string if the failure is in the first name/value pair) if the request was not successful. @param Results A null-terminated Unicode string in format which has all values filled in for the names in the Request string. String to be allocated by the called function. @retval EFI_SUCCESS The Results is filled with the requested values. @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. **/ EFI_STATUS EFIAPI ExtractConfig ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN CONST EFI_STRING Request, OUT EFI_STRING *Progress, OUT EFI_STRING *Results ) { EFI_STATUS Status; UINTN BufferSize; DRIVER_SAMPLE_PRIVATE_DATA *PrivateData; EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting; EFI_STRING ConfigRequest; EFI_STRING ConfigRequestHdr; UINTN Size; EFI_STRING Value; UINTN ValueStrLen; CHAR16 BackupChar; CHAR16 *StrPointer; BOOLEAN AllocatedRequest; if (Progress == NULL || Results == NULL) { return EFI_INVALID_PARAMETER; } // // Initialize the local variables. // ConfigRequestHdr = NULL; ConfigRequest = NULL; Size = 0; *Progress = Request; AllocatedRequest = FALSE; PrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This); HiiConfigRouting = PrivateData->HiiConfigRouting; // // Get Buffer Storage data from EFI variable. // Try to get the current setting from variable. // BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION); Status = gRT->GetVariable ( VariableName, &gDriverSampleFormSetGuid, NULL, &BufferSize, &PrivateData->Configuration ); if (EFI_ERROR (Status)) { return EFI_NOT_FOUND; } if (Request == NULL) { // // Request is set to NULL, construct full request string. // // // Allocate and fill a buffer large enough to hold the template // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator // ConfigRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, VariableName, PrivateData->DriverHandle[0]); Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16); ConfigRequest = AllocateZeroPool (Size); ASSERT (ConfigRequest != NULL); AllocatedRequest = TRUE; UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize); FreePool (ConfigRequestHdr); ConfigRequestHdr = NULL; } else { // // Check routing data in . // Note: if only one Storage is used, then this checking could be skipped. // if (!HiiIsConfigHdrMatch (Request, &gDriverSampleFormSetGuid, NULL)) { return EFI_NOT_FOUND; } // // Check whether request for EFI Varstore. EFI varstore get data // through hii database, not support in this path. // if (HiiIsConfigHdrMatch(Request, &gDriverSampleFormSetGuid, MyEfiVar)) { return EFI_UNSUPPORTED; } if (HiiIsConfigHdrMatch(Request, &gDriverSampleFormSetGuid, MyEfiBitVar)) { return EFI_UNSUPPORTED; } if (HiiIsConfigHdrMatch(Request, &gDriverSampleFormSetGuid, MyEfiUnionVar)) { return EFI_UNSUPPORTED; } // // Set Request to the unified request string. // ConfigRequest = Request; // // Check whether Request includes Request Element. // if (StrStr (Request, L"OFFSET") == NULL) { // // Check Request Element does exist in Reques String // StrPointer = StrStr (Request, L"PATH"); if (StrPointer == NULL) { return EFI_INVALID_PARAMETER; } if (StrStr (StrPointer, L"&") == NULL) { Size = (StrLen (Request) + 32 + 1) * sizeof (CHAR16); ConfigRequest = AllocateZeroPool (Size); ASSERT (ConfigRequest != NULL); AllocatedRequest = TRUE; UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", Request, (UINT64)BufferSize); } } } // // Check if requesting Name/Value storage // if (StrStr (ConfigRequest, L"OFFSET") == NULL) { // // Update Name/Value storage Names // Status = LoadNameValueNames (PrivateData); if (EFI_ERROR (Status)) { return Status; } // // Allocate memory for , e.g. Name0=0x11, Name1=0x1234, Name2="ABCD" // ::=&Name0&Name1&Name2 // ::=&Name0=11&Name1=1234&Name2=0041004200430044 // BufferSize = (StrLen (ConfigRequest) + 1 + sizeof (PrivateData->Configuration.NameValueVar0) * 2 + 1 + sizeof (PrivateData->Configuration.NameValueVar1) * 2 + 1 + sizeof (PrivateData->Configuration.NameValueVar2) * 2 + 1) * sizeof (CHAR16); *Results = AllocateZeroPool (BufferSize); ASSERT (*Results != NULL); StrCpyS (*Results, BufferSize / sizeof (CHAR16), ConfigRequest); Value = *Results; // // Append value of NameValueVar0, type is UINT8 // if ((Value = StrStr (*Results, PrivateData->NameValueName[0])) != NULL) { Value += StrLen (PrivateData->NameValueName[0]); ValueStrLen = ((sizeof (PrivateData->Configuration.NameValueVar0) * 2) + 1); CopyMem (Value + ValueStrLen, Value, StrSize (Value)); BackupChar = Value[ValueStrLen]; *Value++ = L'='; UnicodeValueToStringS ( Value, BufferSize - ((UINTN)Value - (UINTN)*Results), PREFIX_ZERO | RADIX_HEX, PrivateData->Configuration.NameValueVar0, sizeof (PrivateData->Configuration.NameValueVar0) * 2 ); Value += StrnLenS (Value, (BufferSize - ((UINTN)Value - (UINTN)*Results)) / sizeof (CHAR16)); *Value = BackupChar; } // // Append value of NameValueVar1, type is UINT16 // if ((Value = StrStr (*Results, PrivateData->NameValueName[1])) != NULL) { Value += StrLen (PrivateData->NameValueName[1]); ValueStrLen = ((sizeof (PrivateData->Configuration.NameValueVar1) * 2) + 1); CopyMem (Value + ValueStrLen, Value, StrSize (Value)); BackupChar = Value[ValueStrLen]; *Value++ = L'='; UnicodeValueToStringS ( Value, BufferSize - ((UINTN)Value - (UINTN)*Results), PREFIX_ZERO | RADIX_HEX, PrivateData->Configuration.NameValueVar1, sizeof (PrivateData->Configuration.NameValueVar1) * 2 ); Value += StrnLenS (Value, (BufferSize - ((UINTN)Value - (UINTN)*Results)) / sizeof (CHAR16)); *Value = BackupChar; } // // Append value of NameValueVar2, type is CHAR16 * // if ((Value = StrStr (*Results, PrivateData->NameValueName[2])) != NULL) { Value += StrLen (PrivateData->NameValueName[2]); ValueStrLen = StrLen (PrivateData->Configuration.NameValueVar2) * 4 + 1; CopyMem (Value + ValueStrLen, Value, StrSize (Value)); *Value++ = L'='; // // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044" // StrPointer = (CHAR16 *) PrivateData->Configuration.NameValueVar2; for (; *StrPointer != L'\0'; StrPointer++) { UnicodeValueToStringS ( Value, BufferSize - ((UINTN)Value - (UINTN)*Results), PREFIX_ZERO | RADIX_HEX, *StrPointer, 4 ); Value += StrnLenS (Value, (BufferSize - ((UINTN)Value - (UINTN)*Results)) / sizeof (CHAR16)); } } Status = EFI_SUCCESS; } else { // // Convert buffer data to by helper function BlockToConfig() // Status = HiiConfigRouting->BlockToConfig ( HiiConfigRouting, ConfigRequest, (UINT8 *) &PrivateData->Configuration, BufferSize, Results, Progress ); if (!EFI_ERROR (Status)) { ConfigRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, VariableName, PrivateData->DriverHandle[0]); AppendAltCfgString(Results, ConfigRequestHdr); } } // // Free the allocated config request string. // if (AllocatedRequest) { FreePool (ConfigRequest); } if (ConfigRequestHdr != NULL) { FreePool (ConfigRequestHdr); } // // Set Progress string to the original request string. // if (Request == NULL) { *Progress = NULL; } else if (StrStr (Request, L"OFFSET") == NULL) { *Progress = Request + StrLen (Request); } return Status; } /** This function processes the results of changes in configuration. @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param Configuration A null-terminated Unicode string in format. @param Progress A pointer to a string filled in with the offset of the most recent '&' before the first failing name/value pair (or the beginning of the string if the failure is in the first name/value pair) or the terminating NULL if all was successful. @retval EFI_SUCCESS The Results is processed successfully. @retval EFI_INVALID_PARAMETER Configuration is NULL. @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. **/ EFI_STATUS EFIAPI RouteConfig ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN CONST EFI_STRING Configuration, OUT EFI_STRING *Progress ) { EFI_STATUS Status; UINTN BufferSize; DRIVER_SAMPLE_PRIVATE_DATA *PrivateData; EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting; CHAR16 *Value; CHAR16 *StrPtr; CHAR16 TemStr[5]; UINT8 *DataBuffer; UINT8 DigitUint8; UINTN Index; CHAR16 *StrBuffer; if (Configuration == NULL || Progress == NULL) { return EFI_INVALID_PARAMETER; } PrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This); HiiConfigRouting = PrivateData->HiiConfigRouting; *Progress = Configuration; // // Check routing data in . // Note: if only one Storage is used, then this checking could be skipped. // if (!HiiIsConfigHdrMatch (Configuration, &gDriverSampleFormSetGuid, NULL)) { return EFI_NOT_FOUND; } // // Check whether request for EFI Varstore. EFI varstore get data // through hii database, not support in this path. // if (HiiIsConfigHdrMatch(Configuration, &gDriverSampleFormSetGuid, MyEfiVar)) { return EFI_UNSUPPORTED; } if (HiiIsConfigHdrMatch(Configuration, &gDriverSampleFormSetGuid, MyEfiBitVar)) { return EFI_UNSUPPORTED; } if (HiiIsConfigHdrMatch(Configuration, &gDriverSampleFormSetGuid, MyEfiUnionVar)) { return EFI_UNSUPPORTED; } // // Get Buffer Storage data from EFI variable // BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION); Status = gRT->GetVariable ( VariableName, &gDriverSampleFormSetGuid, NULL, &BufferSize, &PrivateData->Configuration ); if (EFI_ERROR (Status)) { return Status; } // // Check if configuring Name/Value storage // if (StrStr (Configuration, L"OFFSET") == NULL) { // // Update Name/Value storage Names // Status = LoadNameValueNames (PrivateData); if (EFI_ERROR (Status)) { return Status; } // // Convert value for NameValueVar0 // if ((Value = StrStr (Configuration, PrivateData->NameValueName[0])) != NULL) { // // Skip "Name=" // Value += StrLen (PrivateData->NameValueName[0]); Value++; // // Get Value String // StrPtr = StrStr (Value, L"&"); if (StrPtr == NULL) { StrPtr = Value + StrLen (Value); } // // Convert Value to Buffer data // DataBuffer = (UINT8 *) &PrivateData->Configuration.NameValueVar0; ZeroMem (TemStr, sizeof (TemStr)); for (Index = 0, StrPtr --; StrPtr >= Value; StrPtr --, Index ++) { TemStr[0] = *StrPtr; DigitUint8 = (UINT8) StrHexToUint64 (TemStr); if ((Index & 1) == 0) { DataBuffer [Index/2] = DigitUint8; } else { DataBuffer [Index/2] = (UINT8) ((UINT8) (DigitUint8 << 4) + DataBuffer [Index/2]); } } } // // Convert value for NameValueVar1 // if ((Value = StrStr (Configuration, PrivateData->NameValueName[1])) != NULL) { // // Skip "Name=" // Value += StrLen (PrivateData->NameValueName[1]); Value++; // // Get Value String // StrPtr = StrStr (Value, L"&"); if (StrPtr == NULL) { StrPtr = Value + StrLen (Value); } // // Convert Value to Buffer data // DataBuffer = (UINT8 *) &PrivateData->Configuration.NameValueVar1; ZeroMem (TemStr, sizeof (TemStr)); for (Index = 0, StrPtr --; StrPtr >= Value; StrPtr --, Index ++) { TemStr[0] = *StrPtr; DigitUint8 = (UINT8) StrHexToUint64 (TemStr); if ((Index & 1) == 0) { DataBuffer [Index/2] = DigitUint8; } else { DataBuffer [Index/2] = (UINT8) ((UINT8) (DigitUint8 << 4) + DataBuffer [Index/2]); } } } // // Convert value for NameValueVar2 // if ((Value = StrStr (Configuration, PrivateData->NameValueName[2])) != NULL) { // // Skip "Name=" // Value += StrLen (PrivateData->NameValueName[2]); Value++; // // Get Value String // StrPtr = StrStr (Value, L"&"); if (StrPtr == NULL) { StrPtr = Value + StrLen (Value); } // // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD" // StrBuffer = (CHAR16 *) PrivateData->Configuration.NameValueVar2; ZeroMem (TemStr, sizeof (TemStr)); while (Value < StrPtr) { StrnCpyS (TemStr, sizeof (TemStr) / sizeof (CHAR16), Value, 4); *(StrBuffer++) = (CHAR16) StrHexToUint64 (TemStr); Value += 4; } *StrBuffer = L'\0'; } // // Store Buffer Storage back to EFI variable // Status = gRT->SetVariable( VariableName, &gDriverSampleFormSetGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, sizeof (DRIVER_SAMPLE_CONFIGURATION), &PrivateData->Configuration ); return Status; } // // Convert to buffer data by helper function ConfigToBlock() // BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION); Status = HiiConfigRouting->ConfigToBlock ( HiiConfigRouting, Configuration, (UINT8 *) &PrivateData->Configuration, &BufferSize, Progress ); if (EFI_ERROR (Status)) { return Status; } // // Store Buffer Storage back to EFI variable // Status = gRT->SetVariable( VariableName, &gDriverSampleFormSetGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, sizeof (DRIVER_SAMPLE_CONFIGURATION), &PrivateData->Configuration ); return Status; } /** This function processes the results of changes in configuration. @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param Action Specifies the type of action taken by the browser. @param QuestionId A unique value which is sent to the original exporting driver so that it can identify the type of data to expect. @param Type The type of value for the question. @param Value A pointer to the data being sent to the original exporting driver. @param ActionRequest On return, points to the action requested by the callback function. @retval EFI_SUCCESS The callback successfully handled the action. @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. @retval EFI_DEVICE_ERROR The variable could not be saved. @retval EFI_UNSUPPORTED The specified Action is not supported by the callback. **/ EFI_STATUS EFIAPI DriverCallback ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN EFI_BROWSER_ACTION Action, IN EFI_QUESTION_ID QuestionId, IN UINT8 Type, IN EFI_IFR_TYPE_VALUE *Value, OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest ) { DRIVER_SAMPLE_PRIVATE_DATA *PrivateData; EFI_STATUS Status; VOID *StartOpCodeHandle; VOID *OptionsOpCodeHandle; EFI_IFR_GUID_LABEL *StartLabel; VOID *EndOpCodeHandle; EFI_IFR_GUID_LABEL *EndLabel; EFI_INPUT_KEY Key; DRIVER_SAMPLE_CONFIGURATION *Configuration; MY_EFI_VARSTORE_DATA *EfiData; EFI_FORM_ID FormId; EFI_STRING Progress; EFI_STRING Results; UINT32 ProgressErr; CHAR16 *TmpStr; UINTN Index; UINT64 BufferValue; EFI_HII_POPUP_SELECTION UserSelection; UserSelection = 0xFF; if (((Value == NULL) && (Action != EFI_BROWSER_ACTION_FORM_OPEN) && (Action != EFI_BROWSER_ACTION_FORM_CLOSE))|| (ActionRequest == NULL)) { return EFI_INVALID_PARAMETER; } FormId = 0; ProgressErr = 0; Status = EFI_SUCCESS; BufferValue = 3; PrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This); switch (Action) { case EFI_BROWSER_ACTION_FORM_OPEN: { if (QuestionId == 0x1234) { // // Sample CallBack for UEFI FORM_OPEN action: // Add Save action into Form 3 when Form 1 is opened. // This will be done only in FORM_OPEN CallBack of question with ID 0x1234 from Form 1. // PrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This); // // Initialize the container for dynamic opcodes // StartOpCodeHandle = HiiAllocateOpCodeHandle (); ASSERT (StartOpCodeHandle != NULL); // // Create Hii Extend Label OpCode as the start opcode // StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL)); StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; StartLabel->Number = LABEL_UPDATE2; HiiCreateActionOpCode ( StartOpCodeHandle, // Container for dynamic created opcodes 0x1238, // Question ID STRING_TOKEN(STR_SAVE_TEXT), // Prompt text STRING_TOKEN(STR_SAVE_TEXT), // Help text EFI_IFR_FLAG_CALLBACK, // Question flag 0 // Action String ID ); HiiUpdateForm ( PrivateData->HiiHandle[0], // HII handle &gDriverSampleFormSetGuid, // Formset GUID 0x3, // Form ID StartOpCodeHandle, // Label for where to insert opcodes NULL // Insert data ); HiiFreeOpCodeHandle (StartOpCodeHandle); } if (QuestionId == 0x1247) { Status = InternalStartMonitor (); ASSERT_EFI_ERROR (Status); } } break; case EFI_BROWSER_ACTION_FORM_CLOSE: { if (QuestionId == 0x5678) { // // Sample CallBack for UEFI FORM_CLOSE action: // Show up a pop-up to specify Form 3 will be closed when exit Form 3. // do { CreatePopUp ( EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"", L"You are going to leave third Form!", L"Press ESC or ENTER to continue ...", L"", NULL ); } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN)); } if (QuestionId == 0x1247) { Status = InternalStopMonitor (); ASSERT_EFI_ERROR (Status); } } break; case EFI_BROWSER_ACTION_RETRIEVE: { switch (QuestionId ) { case 0x1248: if (Type != EFI_IFR_TYPE_REF) { return EFI_INVALID_PARAMETER; } Value->ref.FormId = 0x3; break; case 0x5678: case 0x1247: // // We will reach here once the Question is refreshed // // // Initialize the container for dynamic opcodes // StartOpCodeHandle = HiiAllocateOpCodeHandle (); ASSERT (StartOpCodeHandle != NULL); // // Create Hii Extend Label OpCode as the start opcode // StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL)); StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; if (QuestionId == 0x5678) { StartLabel->Number = LABEL_UPDATE2; FormId = 0x03; PrivateData->Configuration.DynamicRefresh++; } else if (QuestionId == 0x1247 ) { StartLabel->Number = LABEL_UPDATE3; FormId = 0x06; PrivateData->Configuration.RefreshGuidCount++; } HiiCreateActionOpCode ( StartOpCodeHandle, // Container for dynamic created opcodes 0x1237, // Question ID STRING_TOKEN(STR_EXIT_TEXT), // Prompt text STRING_TOKEN(STR_EXIT_TEXT), // Help text EFI_IFR_FLAG_CALLBACK, // Question flag 0 // Action String ID ); HiiUpdateForm ( PrivateData->HiiHandle[0], // HII handle &gDriverSampleFormSetGuid, // Formset GUID FormId, // Form ID StartOpCodeHandle, // Label for where to insert opcodes NULL // Insert data ); HiiFreeOpCodeHandle (StartOpCodeHandle); // // Refresh the Question value // Status = gRT->SetVariable( VariableName, &gDriverSampleFormSetGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, sizeof (DRIVER_SAMPLE_CONFIGURATION), &PrivateData->Configuration ); if (QuestionId == 0x5678) { // // Update uncommitted data of Browser // EfiData = AllocateZeroPool (sizeof (MY_EFI_VARSTORE_DATA)); ASSERT (EfiData != NULL); if (HiiGetBrowserData (&gDriverSampleFormSetGuid, MyEfiVar, sizeof (MY_EFI_VARSTORE_DATA), (UINT8 *) EfiData)) { EfiData->Field8 = 111; HiiSetBrowserData ( &gDriverSampleFormSetGuid, MyEfiVar, sizeof (MY_EFI_VARSTORE_DATA), (UINT8 *) EfiData, NULL ); } FreePool (EfiData); } break; } } break; case EFI_BROWSER_ACTION_DEFAULT_STANDARD: { switch (QuestionId) { case 0x1240: Value->u8 = DEFAULT_CLASS_STANDARD_VALUE; break; case 0x1252: for (Index = 0; Index < 3; Index ++) { SetArrayData (Value, EFI_IFR_TYPE_NUM_SIZE_8, Index, BufferValue--); } break; case 0x6666: Value->u8 = 12; break; default: Status = EFI_UNSUPPORTED; break; } } break; case EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING: { switch (QuestionId) { case 0x1240: Value->u8 = DEFAULT_CLASS_MANUFACTURING_VALUE; break; case 0x6666: Value->u8 = 13; break; default: Status = EFI_UNSUPPORTED; break; } } break; case EFI_BROWSER_ACTION_CHANGING: { switch (QuestionId) { case 0x1249: { if (Type != EFI_IFR_TYPE_REF) { return EFI_INVALID_PARAMETER; } Value->ref.FormId = 0x1234; } break; case 0x1234: // // Initialize the container for dynamic opcodes // StartOpCodeHandle = HiiAllocateOpCodeHandle (); ASSERT (StartOpCodeHandle != NULL); EndOpCodeHandle = HiiAllocateOpCodeHandle (); ASSERT (EndOpCodeHandle != NULL); // // Create Hii Extend Label OpCode as the start opcode // StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL)); StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; StartLabel->Number = LABEL_UPDATE1; // // Create Hii Extend Label OpCode as the end opcode // EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL)); EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; EndLabel->Number = LABEL_END; HiiCreateActionOpCode ( StartOpCodeHandle, // Container for dynamic created opcodes 0x1237, // Question ID STRING_TOKEN(STR_EXIT_TEXT), // Prompt text STRING_TOKEN(STR_EXIT_TEXT), // Help text EFI_IFR_FLAG_CALLBACK, // Question flag 0 // Action String ID ); // // Create Option OpCode // OptionsOpCodeHandle = HiiAllocateOpCodeHandle (); ASSERT (OptionsOpCodeHandle != NULL); HiiCreateOneOfOptionOpCode ( OptionsOpCodeHandle, STRING_TOKEN (STR_BOOT_OPTION1), 0, EFI_IFR_NUMERIC_SIZE_1, 1 ); HiiCreateOneOfOptionOpCode ( OptionsOpCodeHandle, STRING_TOKEN (STR_BOOT_OPTION2), 0, EFI_IFR_NUMERIC_SIZE_1, 2 ); // // Prepare initial value for the dynamic created oneof Question // PrivateData->Configuration.DynamicOneof = 2; Status = gRT->SetVariable( VariableName, &gDriverSampleFormSetGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, sizeof (DRIVER_SAMPLE_CONFIGURATION), &PrivateData->Configuration ); // // Set initial vlaue of dynamic created oneof Question in Form Browser // Configuration = AllocateZeroPool (sizeof (DRIVER_SAMPLE_CONFIGURATION)); ASSERT (Configuration != NULL); if (HiiGetBrowserData (&gDriverSampleFormSetGuid, VariableName, sizeof (DRIVER_SAMPLE_CONFIGURATION), (UINT8 *) Configuration)) { Configuration->DynamicOneof = 2; // // Update uncommitted data of Browser // HiiSetBrowserData ( &gDriverSampleFormSetGuid, VariableName, sizeof (DRIVER_SAMPLE_CONFIGURATION), (UINT8 *) Configuration, NULL ); } FreePool (Configuration); HiiCreateOneOfOpCode ( StartOpCodeHandle, // Container for dynamic created opcodes 0x8001, // Question ID (or call it "key") CONFIGURATION_VARSTORE_ID, // VarStore ID (UINT16) DYNAMIC_ONE_OF_VAR_OFFSET, // Offset in Buffer Storage STRING_TOKEN (STR_ONE_OF_PROMPT), // Question prompt text STRING_TOKEN (STR_ONE_OF_HELP), // Question help text EFI_IFR_FLAG_CALLBACK, // Question flag EFI_IFR_NUMERIC_SIZE_1, // Data type of Question Value OptionsOpCodeHandle, // Option Opcode list NULL // Default Opcode is NULl ); HiiCreateOrderedListOpCode ( StartOpCodeHandle, // Container for dynamic created opcodes 0x8002, // Question ID CONFIGURATION_VARSTORE_ID, // VarStore ID (UINT16) DYNAMIC_ORDERED_LIST_VAR_OFFSET, // Offset in Buffer Storage STRING_TOKEN (STR_BOOT_OPTIONS), // Question prompt text STRING_TOKEN (STR_BOOT_OPTIONS), // Question help text EFI_IFR_FLAG_RESET_REQUIRED, // Question flag 0, // Ordered list flag, e.g. EFI_IFR_UNIQUE_SET EFI_IFR_NUMERIC_SIZE_1, // Data type of Question value 5, // Maximum container OptionsOpCodeHandle, // Option Opcode list NULL // Default Opcode is NULl ); HiiCreateTextOpCode ( StartOpCodeHandle, STRING_TOKEN(STR_TEXT_SAMPLE_HELP), STRING_TOKEN(STR_TEXT_SAMPLE_HELP), STRING_TOKEN(STR_TEXT_SAMPLE_STRING) ); HiiCreateDateOpCode ( StartOpCodeHandle, 0x8004, 0x0, 0x0, STRING_TOKEN(STR_DATE_SAMPLE_HELP), STRING_TOKEN(STR_DATE_SAMPLE_HELP), 0, QF_DATE_STORAGE_TIME, NULL ); HiiCreateTimeOpCode ( StartOpCodeHandle, 0x8005, 0x0, 0x0, STRING_TOKEN(STR_TIME_SAMPLE_HELP), STRING_TOKEN(STR_TIME_SAMPLE_HELP), 0, QF_TIME_STORAGE_TIME, NULL ); HiiCreateGotoOpCode ( StartOpCodeHandle, // Container for dynamic created opcodes 1, // Target Form ID STRING_TOKEN (STR_GOTO_FORM1), // Prompt text STRING_TOKEN (STR_GOTO_HELP), // Help text 0, // Question flag 0x8003 // Question ID ); HiiUpdateForm ( PrivateData->HiiHandle[0], // HII handle &gDriverSampleFormSetGuid, // Formset GUID 0x1234, // Form ID StartOpCodeHandle, // Label for where to insert opcodes EndOpCodeHandle // Replace data ); HiiFreeOpCodeHandle (StartOpCodeHandle); HiiFreeOpCodeHandle (OptionsOpCodeHandle); HiiFreeOpCodeHandle (EndOpCodeHandle); break; default: break; } } break; case EFI_BROWSER_ACTION_CHANGED: switch (QuestionId) { case 0x1237: // // User press "Exit now", request Browser to exit // *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; break; case 0x1238: // // User press "Save now", request Browser to save the uncommitted data. // *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT; break; case 0x1241: case 0x1246: // // User press "Submit current form and Exit now", request Browser to submit current form and exit // *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT; break; case 0x1242: // // User press "Discard current form now", request Browser to discard the uncommitted data. // *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD; break; case 0x1243: // // User press "Submit current form now", request Browser to save the uncommitted data. // *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; break; case 0x1244: case 0x1245: // // User press "Discard current form and Exit now", request Browser to discard the uncommitted data and exit. // *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT; break; case 0x1231: // // 1. Check to see whether system support keyword. // Status = PrivateData->HiiKeywordHandler->GetData (PrivateData->HiiKeywordHandler, L"NAMESPACE=x-UEFI-ns", L"KEYWORD=iSCSIBootEnable", &Progress, &ProgressErr, &Results ); if (EFI_ERROR (Status)) { do { CreatePopUp ( EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"", L"This system not support this keyword!", L"Press ENTER to continue ...", L"", NULL ); } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); Status = EFI_SUCCESS; break; } // // 2. If system support this keyword, just try to change value. // // // Change value from '0' to '1' or from '1' to '0' // TmpStr = StrStr (Results, L"&VALUE="); ASSERT (TmpStr != NULL); TmpStr += StrLen (L"&VALUE="); TmpStr++; if (*TmpStr == L'0') { *TmpStr = L'1'; } else { *TmpStr = L'0'; } // // 3. Call the keyword handler protocol to change the value. // Status = PrivateData->HiiKeywordHandler->SetData (PrivateData->HiiKeywordHandler, Results, &Progress, &ProgressErr ); if (EFI_ERROR (Status)) { do { CreatePopUp ( EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"", L"Set keyword to the system failed!", L"Press ENTER to continue ...", L"", NULL ); } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); Status = EFI_SUCCESS; break; } break; case 0x1330: Status = mPrivateData->HiiPopup->CreatePopup ( mPrivateData->HiiPopup, EfiHiiPopupStyleInfo, EfiHiiPopupTypeYesNo, mPrivateData->HiiHandle[0], STRING_TOKEN (STR_POPUP_STRING), &UserSelection ); if (!EFI_ERROR (Status)) { if (UserSelection == EfiHiiPopupSelectionYes) { *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; } } break; default: break; } break; case EFI_BROWSER_ACTION_SUBMITTED: { if (QuestionId == 0x1250) { // // Sample CallBack for EFI_BROWSER_ACTION_SUBMITTED action: // Show up a pop-up to show SUBMITTED callback has been triggered. // do { CreatePopUp ( EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"", L"EfiVarstore value has been submitted!", L"Press ESC or ENTER to continue ...", L"", NULL ); } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN)); } } break; default: Status = EFI_UNSUPPORTED; break; } return Status; } /** Main entry for this driver. @param ImageHandle Image handle this driver. @param SystemTable Pointer to SystemTable. @retval EFI_SUCESS This function always complete successfully. **/ EFI_STATUS EFIAPI DriverSampleInit ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; EFI_HII_HANDLE HiiHandle[2]; EFI_SCREEN_DESCRIPTOR Screen; EFI_HII_DATABASE_PROTOCOL *HiiDatabase; EFI_HII_STRING_PROTOCOL *HiiString; EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2; EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting; EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *HiiKeywordHandler; EFI_HII_POPUP_PROTOCOL *PopupHandler; CHAR16 *NewString; UINTN BufferSize; DRIVER_SAMPLE_CONFIGURATION *Configuration; BOOLEAN ActionFlag; EFI_STRING ConfigRequestHdr; EFI_STRING NameRequestHdr; MY_EFI_VARSTORE_DATA *VarStoreConfig; MY_EFI_BITS_VARSTORE_DATA *BitsVarStoreConfig; MY_EFI_UNION_DATA *UnionConfig; EFI_INPUT_KEY HotKey; EDKII_FORM_BROWSER_EXTENSION_PROTOCOL *FormBrowserEx; // // Initialize the local variables. // ConfigRequestHdr = NULL; NewString = NULL; // // Initialize screen dimensions for SendForm(). // Remove 3 characters from top and bottom // ZeroMem (&Screen, sizeof (EFI_SCREEN_DESCRIPTOR)); gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Screen.RightColumn, &Screen.BottomRow); Screen.TopRow = 3; Screen.BottomRow = Screen.BottomRow - 3; // // Initialize driver private data // mPrivateData = AllocateZeroPool (sizeof (DRIVER_SAMPLE_PRIVATE_DATA)); if (mPrivateData == NULL) { return EFI_OUT_OF_RESOURCES; } mPrivateData->Signature = DRIVER_SAMPLE_PRIVATE_SIGNATURE; mPrivateData->ConfigAccess.ExtractConfig = ExtractConfig; mPrivateData->ConfigAccess.RouteConfig = RouteConfig; mPrivateData->ConfigAccess.Callback = DriverCallback; // // Locate Hii Database protocol // Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &HiiDatabase); if (EFI_ERROR (Status)) { return Status; } mPrivateData->HiiDatabase = HiiDatabase; // // Locate HiiString protocol // Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString); if (EFI_ERROR (Status)) { return Status; } mPrivateData->HiiString = HiiString; // // Locate Formbrowser2 protocol // Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2); if (EFI_ERROR (Status)) { return Status; } mPrivateData->FormBrowser2 = FormBrowser2; // // Locate ConfigRouting protocol // Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting); if (EFI_ERROR (Status)) { return Status; } mPrivateData->HiiConfigRouting = HiiConfigRouting; // // Locate keyword handler protocol // Status = gBS->LocateProtocol (&gEfiConfigKeywordHandlerProtocolGuid, NULL, (VOID **) &HiiKeywordHandler); if (EFI_ERROR (Status)) { return Status; } mPrivateData->HiiKeywordHandler = HiiKeywordHandler; // // Locate HiiPopup protocol // Status = gBS->LocateProtocol (&gEfiHiiPopupProtocolGuid, NULL, (VOID **) &PopupHandler); if (EFI_ERROR (Status)) { return Status; } mPrivateData->HiiPopup = PopupHandler; Status = gBS->InstallMultipleProtocolInterfaces ( &DriverHandle[0], &gEfiDevicePathProtocolGuid, &mHiiVendorDevicePath0, &gEfiHiiConfigAccessProtocolGuid, &mPrivateData->ConfigAccess, NULL ); ASSERT_EFI_ERROR (Status); mPrivateData->DriverHandle[0] = DriverHandle[0]; // // Publish our HII data // HiiHandle[0] = HiiAddPackages ( &gDriverSampleFormSetGuid, DriverHandle[0], DriverSampleStrings, VfrBin, NULL ); if (HiiHandle[0] == NULL) { return EFI_OUT_OF_RESOURCES; } mPrivateData->HiiHandle[0] = HiiHandle[0]; // // Publish another Fromset // Status = gBS->InstallMultipleProtocolInterfaces ( &DriverHandle[1], &gEfiDevicePathProtocolGuid, &mHiiVendorDevicePath1, &gEfiHiiConfigAccessProtocolGuid, &mPrivateData->ConfigAccess, NULL ); ASSERT_EFI_ERROR (Status); mPrivateData->DriverHandle[1] = DriverHandle[1]; HiiHandle[1] = HiiAddPackages ( &gDriverSampleInventoryGuid, DriverHandle[1], DriverSampleStrings, InventoryBin, NULL ); if (HiiHandle[1] == NULL) { DriverSampleUnload (ImageHandle); return EFI_OUT_OF_RESOURCES; } mPrivateData->HiiHandle[1] = HiiHandle[1]; // // Update the device path string. // NewString = ConvertDevicePathToText((EFI_DEVICE_PATH_PROTOCOL*)&mHiiVendorDevicePath0, FALSE, FALSE); if (HiiSetString (HiiHandle[0], STRING_TOKEN (STR_DEVICE_PATH), NewString, NULL) == 0) { DriverSampleUnload (ImageHandle); return EFI_OUT_OF_RESOURCES; } if (NewString != NULL) { FreePool (NewString); } // // Very simple example of how one would update a string that is already // in the HII database // NewString = L"700 Mhz"; if (HiiSetString (HiiHandle[0], STRING_TOKEN (STR_CPU_STRING2), NewString, NULL) == 0) { DriverSampleUnload (ImageHandle); return EFI_OUT_OF_RESOURCES; } HiiSetString (HiiHandle[0], 0, NewString, NULL); // // Initialize Name/Value name String ID // mPrivateData->NameStringId[0] = STR_NAME_VALUE_VAR_NAME0; mPrivateData->NameStringId[1] = STR_NAME_VALUE_VAR_NAME1; mPrivateData->NameStringId[2] = STR_NAME_VALUE_VAR_NAME2; // // Initialize configuration data // Configuration = &mPrivateData->Configuration; ZeroMem (Configuration, sizeof (DRIVER_SAMPLE_CONFIGURATION)); // // Try to read NV config EFI variable first // ConfigRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, VariableName, DriverHandle[0]); ASSERT (ConfigRequestHdr != NULL); NameRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, NULL, DriverHandle[0]); ASSERT (NameRequestHdr != NULL); BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION); Status = gRT->GetVariable (VariableName, &gDriverSampleFormSetGuid, NULL, &BufferSize, Configuration); if (EFI_ERROR (Status)) { // // Store zero data Buffer Storage to EFI variable // Status = gRT->SetVariable( VariableName, &gDriverSampleFormSetGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, sizeof (DRIVER_SAMPLE_CONFIGURATION), Configuration ); if (EFI_ERROR (Status)) { DriverSampleUnload (ImageHandle); return Status; } // // EFI variable for NV config doesn't exit, we should build this variable // based on default values stored in IFR // ActionFlag = HiiSetToDefaults (NameRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD); if (!ActionFlag) { DriverSampleUnload (ImageHandle); return EFI_INVALID_PARAMETER; } ActionFlag = HiiSetToDefaults (ConfigRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD); if (!ActionFlag) { DriverSampleUnload (ImageHandle); return EFI_INVALID_PARAMETER; } } else { // // EFI variable does exist and Validate Current Setting // ActionFlag = HiiValidateSettings (NameRequestHdr); if (!ActionFlag) { DriverSampleUnload (ImageHandle); return EFI_INVALID_PARAMETER; } ActionFlag = HiiValidateSettings (ConfigRequestHdr); if (!ActionFlag) { DriverSampleUnload (ImageHandle); return EFI_INVALID_PARAMETER; } } FreePool (ConfigRequestHdr); // // Initialize efi varstore configuration data // VarStoreConfig = &mPrivateData->VarStoreConfig; ZeroMem (VarStoreConfig, sizeof (MY_EFI_VARSTORE_DATA)); ConfigRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, MyEfiVar, DriverHandle[0]); ASSERT (ConfigRequestHdr != NULL); BufferSize = sizeof (MY_EFI_VARSTORE_DATA); Status = gRT->GetVariable (MyEfiVar, &gDriverSampleFormSetGuid, NULL, &BufferSize, VarStoreConfig); if (EFI_ERROR (Status)) { // // Store zero data to EFI variable Storage. // Status = gRT->SetVariable( MyEfiVar, &gDriverSampleFormSetGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, sizeof (MY_EFI_VARSTORE_DATA), VarStoreConfig ); if (EFI_ERROR (Status)) { DriverSampleUnload (ImageHandle); return Status; } // // EFI variable for NV config doesn't exit, we should build this variable // based on default values stored in IFR // ActionFlag = HiiSetToDefaults (ConfigRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD); if (!ActionFlag) { DriverSampleUnload (ImageHandle); return EFI_INVALID_PARAMETER; } } else { // // EFI variable does exist and Validate Current Setting // ActionFlag = HiiValidateSettings (ConfigRequestHdr); if (!ActionFlag) { DriverSampleUnload (ImageHandle); return EFI_INVALID_PARAMETER; } } FreePool (ConfigRequestHdr); // // Initialize Bits efi varstore configuration data // BitsVarStoreConfig = &mPrivateData->BitsVarStoreConfig; ZeroMem (BitsVarStoreConfig, sizeof (MY_EFI_BITS_VARSTORE_DATA)); ConfigRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, MyEfiBitVar, DriverHandle[0]); ASSERT (ConfigRequestHdr != NULL); BufferSize = sizeof (MY_EFI_BITS_VARSTORE_DATA); Status = gRT->GetVariable (MyEfiBitVar, &gDriverSampleFormSetGuid, NULL, &BufferSize, BitsVarStoreConfig); if (EFI_ERROR (Status)) { // // Store zero data to EFI variable Storage. // Status = gRT->SetVariable( MyEfiBitVar, &gDriverSampleFormSetGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, sizeof (MY_EFI_BITS_VARSTORE_DATA), BitsVarStoreConfig ); if (EFI_ERROR (Status)) { DriverSampleUnload (ImageHandle); return Status; } // // EFI variable for NV config doesn't exit, we should build this variable // based on default values stored in IFR // ActionFlag = HiiSetToDefaults (ConfigRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD); if (!ActionFlag) { DriverSampleUnload (ImageHandle); return EFI_INVALID_PARAMETER; } } else { // // EFI variable does exist and Validate Current Setting // ActionFlag = HiiValidateSettings (ConfigRequestHdr); if (!ActionFlag) { DriverSampleUnload (ImageHandle); return EFI_INVALID_PARAMETER; } } FreePool (ConfigRequestHdr); // // Initialize Union efi varstore configuration data // UnionConfig = &mPrivateData->UnionConfig; ZeroMem (UnionConfig, sizeof (MY_EFI_UNION_DATA)); ConfigRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, MyEfiUnionVar, DriverHandle[0]); ASSERT (ConfigRequestHdr != NULL); BufferSize = sizeof (MY_EFI_UNION_DATA); Status = gRT->GetVariable (MyEfiUnionVar, &gDriverSampleFormSetGuid, NULL, &BufferSize, UnionConfig); if (EFI_ERROR (Status)) { // // Store zero data to EFI variable Storage. // Status = gRT->SetVariable( MyEfiUnionVar, &gDriverSampleFormSetGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, sizeof (MY_EFI_UNION_DATA), UnionConfig ); if (EFI_ERROR (Status)) { DriverSampleUnload (ImageHandle); return Status; } // // EFI variable for NV config doesn't exit, we should build this variable // based on default values stored in IFR // ActionFlag = HiiSetToDefaults (ConfigRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD); if (!ActionFlag) { DriverSampleUnload (ImageHandle); return EFI_INVALID_PARAMETER; } } else { // // EFI variable does exist and Validate Current Setting // ActionFlag = HiiValidateSettings (ConfigRequestHdr); if (!ActionFlag) { DriverSampleUnload (ImageHandle); return EFI_INVALID_PARAMETER; } } FreePool (ConfigRequestHdr); Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, EfiEventEmptyFunction, NULL, &gEfiIfrRefreshIdOpGuid, &mEvent ); ASSERT_EFI_ERROR (Status); // // Example of how to use BrowserEx protocol to register HotKey. // Status = gBS->LocateProtocol (&gEdkiiFormBrowserExProtocolGuid, NULL, (VOID **) &FormBrowserEx); if (!EFI_ERROR (Status)) { // // First unregister the default hot key F9 and F10. // HotKey.UnicodeChar = CHAR_NULL; HotKey.ScanCode = SCAN_F9; FormBrowserEx->RegisterHotKey (&HotKey, 0, 0, NULL); HotKey.ScanCode = SCAN_F10; FormBrowserEx->RegisterHotKey (&HotKey, 0, 0, NULL); // // Register the default HotKey F9 and F10 again. // HotKey.ScanCode = SCAN_F10; NewString = HiiGetString (mPrivateData->HiiHandle[0], STRING_TOKEN (FUNCTION_TEN_STRING), NULL); ASSERT (NewString != NULL); FormBrowserEx->RegisterHotKey (&HotKey, BROWSER_ACTION_SUBMIT, 0, NewString); HotKey.ScanCode = SCAN_F9; NewString = HiiGetString (mPrivateData->HiiHandle[0], STRING_TOKEN (FUNCTION_NINE_STRING), NULL); ASSERT (NewString != NULL); FormBrowserEx->RegisterHotKey (&HotKey, BROWSER_ACTION_DEFAULT, EFI_HII_DEFAULT_CLASS_STANDARD, NewString); } // // In default, this driver is built into Flash device image, // the following code doesn't run. // // // Example of how to display only the item we sent to HII // When this driver is not built into Flash device image, // it need to call SendForm to show front page by itself. // if (DISPLAY_ONLY_MY_ITEM <= 1) { // // Have the browser pull out our copy of the data, and only display our data // Status = FormBrowser2->SendForm ( FormBrowser2, &(HiiHandle[DISPLAY_ONLY_MY_ITEM]), 1, NULL, 0, NULL, NULL ); HiiRemovePackages (HiiHandle[0]); HiiRemovePackages (HiiHandle[1]); } return EFI_SUCCESS; } /** Unloads the application and its installed protocol. @param[in] ImageHandle Handle that identifies the image to be unloaded. @retval EFI_SUCCESS The image has been unloaded. **/ EFI_STATUS EFIAPI DriverSampleUnload ( IN EFI_HANDLE ImageHandle ) { UINTN Index; ASSERT (mPrivateData != NULL); if (DriverHandle[0] != NULL) { gBS->UninstallMultipleProtocolInterfaces ( DriverHandle[0], &gEfiDevicePathProtocolGuid, &mHiiVendorDevicePath0, &gEfiHiiConfigAccessProtocolGuid, &mPrivateData->ConfigAccess, NULL ); DriverHandle[0] = NULL; } if (DriverHandle[1] != NULL) { gBS->UninstallMultipleProtocolInterfaces ( DriverHandle[1], &gEfiDevicePathProtocolGuid, &mHiiVendorDevicePath1, &gEfiHiiConfigAccessProtocolGuid, &mPrivateData->ConfigAccess, NULL ); DriverHandle[1] = NULL; } if (mPrivateData->HiiHandle[0] != NULL) { HiiRemovePackages (mPrivateData->HiiHandle[0]); } if (mPrivateData->HiiHandle[1] != NULL) { HiiRemovePackages (mPrivateData->HiiHandle[1]); } for (Index = 0; Index < NAME_VALUE_NAME_NUMBER; Index++) { if (mPrivateData->NameValueName[Index] != NULL) { FreePool (mPrivateData->NameValueName[Index]); } } FreePool (mPrivateData); mPrivateData = NULL; gBS->CloseEvent (mEvent); return EFI_SUCCESS; }