/** @file L05GraphicNovoMenu.c ;****************************************************************************** ;* Copyright (c) 2012-2018, Insyde Software Corporation. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** */ #include "L05GraphicNovoMenu.h" EFI_FORM_BROWSER2_PROTOCOL *gL05NovoMenuFormBrowser2; UINT16 mKeyInput; HII_VENDOR_DEVICE_PATH mNovoMenuHiiVendorDevicePath = { { { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { (UINT8) (sizeof (VENDOR_DEVICE_PATH)), (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) } }, L05_NOVO_MENU_FORMSET_GUID }, { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { (UINT8) (END_DEVICE_PATH_LENGTH), (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) } } }; L05_NOVO_MENU_CALLBACK_DATA gL05NovoMenuPrivate = { L05_NOVO_MENU_CALLBACK_DATA_SIGNATURE, NULL, NULL, { NovoMenuFakeExtractConfig, NovoMenuFakeRouteConfig, NovoMenuCallback } }; /** 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 NovoMenuFakeExtractConfig ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN CONST EFI_STRING Request, OUT EFI_STRING *Progress, OUT EFI_STRING *Results ) { if (Progress == NULL || Results == NULL) { return EFI_INVALID_PARAMETER; } *Progress = Request; return EFI_NOT_FOUND; } /** 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 NovoMenuFakeRouteConfig ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN CONST EFI_STRING Configuration, OUT EFI_STRING *Progress ) { if (Configuration == NULL || Progress == NULL) { return EFI_INVALID_PARAMETER; } *Progress = Configuration; *Progress = Configuration + StrLen (Configuration); return EFI_SUCCESS; } /** This call back function is registered with Novo Menu formset. When user selects a boot option, this call back function will be triggered. The boot option is saved for later processing. @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_INVALID_PARAMETER The setup browser call this function with invalid parameters. **/ EFI_STATUS EFIAPI NovoMenuCallback ( 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 ) { if (Action == EFI_BROWSER_ACTION_CHANGED) { if ((Value == NULL) || (ActionRequest == NULL)) { return EFI_INVALID_PARAMETER; } mKeyInput = QuestionId; // // Request to exit SendForm(), so that we could boot the selected option // *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; return EFI_SUCCESS; } // // All other action return unsupported. // return EFI_UNSUPPORTED; } /** Registers HII packages for the Novo Menu to HII Database. It also registers the browser call back function. @retval EFI_SUCCESS HII packages for the Novo Menu were registered successfully. @retval EFI_OUT_OF_RESOURCES HII packages for the Novo Menu failed to be registered. **/ EFI_STATUS InitializeNovoMenu ( VOID ) { EFI_STATUS Status; Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, &gL05NovoMenuFormBrowser2); if (EFI_ERROR (Status)) { return Status; } // // Install Device Path Protocol and Config Access protocol to driver handle // Status = gBS->InstallMultipleProtocolInterfaces ( &gL05NovoMenuPrivate.DriverHandle, &gEfiDevicePathProtocolGuid, &mNovoMenuHiiVendorDevicePath, &gEfiHiiConfigAccessProtocolGuid, &gL05NovoMenuPrivate.ConfigAccess, NULL ); ASSERT_EFI_ERROR (Status); // // Publish our HII data // gL05NovoMenuPrivate.HiiHandle = HiiAddPackages ( &gL05NovoMenuFormSetGuid, gL05NovoMenuPrivate.DriverHandle, L05GraphicNovoMenuVfrBin, L05DxeServiceBodyStrings, NULL ); if (gL05NovoMenuPrivate.HiiHandle == NULL) { Status = EFI_OUT_OF_RESOURCES; } else { Status = EFI_SUCCESS; } return Status; } /** This function invokes Novo Menu. If all devices have not a chance to be connected, the connect all will be triggered. It then enumerate all boot options. If a boot option from the Novo Menu page is selected, Novo Menu will boot from this boot option. **/ EFI_STATUS L05GraphicNovoButtonMenu ( IN OUT UINTN *L05NovoButtonMenuSelection ) { EFI_STATUS Status; EFI_HII_HANDLE HiiHandle; EFI_BROWSER_ACTION_REQUEST ActionRequest; VOID *StartOpCodeHandle; VOID *EndOpCodeHandle; EFI_IFR_GUID_LABEL *StartLabel; EFI_IFR_GUID_LABEL *EndLabel; UINTN Index; UINTN L05NovoOptionCount; EFI_STRING_ID L05NovoOptionList[] = { 0, STRING_TOKEN (STR_NORMAL_STARTUP), STRING_TOKEN (STR_BIOS_SETUP), STRING_TOKEN (STR_BOOT_MENU), STRING_TOKEN (STR_SYSTEM_RECOVERY), STRING_TOKEN (STR_UEFI_DIAGNOSTICS), }; BOOLEAN FindSystemRecovery; BOOLEAN FindDiagnostics; EFI_STRING_ID L05NovoOptionRecovery; EFI_STRING_ID L05NovoOptionDiagnostics; L05NovoOptionCount = 0; FindSystemRecovery = FALSE; FindDiagnostics = FALSE; L05NovoOptionRecovery = STRING_TOKEN (STR_SYSTEM_RECOVERY); L05NovoOptionDiagnostics = STRING_TOKEN (STR_UEFI_DIAGNOSTICS); #ifdef L05_ONE_KEY_RECOVERY_ENABLE FindSystemRecovery = FindSystemRecovery | IsOkrSystemRecovery (); #endif #ifdef L05_PUSH_BUTTON_RESET_ENABLE FindSystemRecovery = FindSystemRecovery | IsPbrSystemRecovery (); #endif #ifdef L05_DIAGNOSTICS_SUPPORT FindDiagnostics = TRUE; #endif Status = InitializeNovoMenu (); PcdSetBoolS (PcdL05NovoMenuEntryFlag, TRUE); HiiHandle = gL05NovoMenuPrivate.HiiHandle; // // Allocate space for creation of UpdateData Buffer // 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_L05_NOVO_MENU_START; // // 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_L05_NOVO_MENU_END; L05NovoOptionCount = (sizeof (L05NovoOptionList) / sizeof (EFI_STRING_ID)); for (Index = 1; Index < L05NovoOptionCount; Index++) { if (((!FindSystemRecovery) && (CompareMem (&L05NovoOptionList[Index], &L05NovoOptionRecovery, sizeof (L05NovoOptionRecovery)) == 0)) || ((!FindDiagnostics) && (CompareMem (&L05NovoOptionList[Index], &L05NovoOptionDiagnostics, sizeof (L05NovoOptionDiagnostics)) == 0))) { // // 1. [Lenovo China Minimum BIOS Spec 1.39] // [3.3.3.3 Novo button power on Menu] // 5 System Recovery item must be hidden if the recovery partition do not exist. // 2. Skip inactive items. // continue; } HiiCreateActionOpCode ( StartOpCodeHandle, (UINT16) Index, L05NovoOptionList[Index], 0, EFI_IFR_FLAG_CALLBACK, 0 ); } HiiUpdateForm ( HiiHandle, &gL05NovoMenuFormSetGuid, L05_NOVO_MENU_FORM_ID, StartOpCodeHandle, EndOpCodeHandle ); HiiFreeOpCodeHandle (StartOpCodeHandle); HiiFreeOpCodeHandle (EndOpCodeHandle); ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; Status = gL05NovoMenuFormBrowser2->SendForm ( gL05NovoMenuFormBrowser2, &HiiHandle, 1, &gL05NovoMenuFormSetGuid, 0, NULL, &ActionRequest ); *L05NovoButtonMenuSelection = mKeyInput - 1; PcdSetBoolS (PcdL05NovoMenuEntryFlag, FALSE); return Status; }