--- /dev/null
+/*++\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ DeviceManager.c\r
+\r
+Abstract:\r
+\r
+ The platform device manager reference implement\r
+\r
+--*/\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+#include "DeviceManager.h"\r
+\r
+STATIC UINT16 mTokenCount;\r
+EFI_FRONTPAGE_CALLBACK_INFO FPCallbackInfo;\r
+extern UINTN gCallbackKey;\r
+extern EFI_FORM_BROWSER_PROTOCOL *gBrowser;\r
+extern EFI_GUID gBdsStringPackGuid;\r
+extern BOOLEAN gConnectAllHappened;\r
+\r
+STRING_REF gStringTokenTable[] = {\r
+ STR_VIDEO_DEVICE,\r
+ STR_NETWORK_DEVICE,\r
+ STR_INPUT_DEVICE,\r
+ STR_ON_BOARD_DEVICE,\r
+ STR_OTHER_DEVICE,\r
+ STR_EMPTY_STRING,\r
+ 0xFFFF\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceManagerCallbackRoutine (\r
+ IN EFI_FORM_CALLBACK_PROTOCOL *This,\r
+ IN UINT16 KeyValue,\r
+ IN EFI_IFR_DATA_ARRAY *DataArray,\r
+ OUT EFI_HII_CALLBACK_PACKET **Packet\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This is the function that is called to provide results data to the driver. This data\r
+ consists of a unique key which is used to identify what data is either being passed back\r
+ or being asked for.\r
+\r
+Arguments:\r
+\r
+ KeyValue - A unique value which is sent to the original exporting driver so that it\r
+ can identify the type of data to expect. The format of the data tends to\r
+ vary based on the op-code that geerated the callback.\r
+\r
+ Data - A pointer to the data being sent to the original exporting driver.\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+ //\r
+ // The KeyValue corresponds in this case to the handle which was requested to be displayed\r
+ //\r
+ EFI_FRONTPAGE_CALLBACK_INFO *CallbackInfo;\r
+\r
+ CallbackInfo = EFI_FP_CALLBACK_DATA_FROM_THIS (This);\r
+ switch (KeyValue) {\r
+ case 0x2000:\r
+ CallbackInfo->Data.VideoBIOS = (UINT8) (UINTN) (((EFI_IFR_DATA_ENTRY *)(DataArray + 1))->Data);\r
+ gRT->SetVariable (\r
+ L"VBIOS",\r
+ &gEfiGenericPlatformVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ sizeof (UINT8),\r
+ &CallbackInfo->Data.VideoBIOS\r
+ );\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ gCallbackKey = KeyValue;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+InitializeDeviceManager (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Initialize HII information for the FrontPage\r
+\r
+Arguments:\r
+ None\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HII_PACKAGES *PackageList;\r
+ EFI_HII_UPDATE_DATA *UpdateData;\r
+\r
+ //\r
+ // Allocate space for creation of UpdateData Buffer\r
+ //\r
+ UpdateData = AllocateZeroPool (0x1000);\r
+ ASSERT (UpdateData != NULL);\r
+\r
+ PackageList = PreparePackages (1, &gBdsStringPackGuid, DeviceManagerVfrBin);\r
+ Status = Hii->NewPack (Hii, PackageList, &FPCallbackInfo.DevMgrHiiHandle);\r
+ FreePool (PackageList);\r
+\r
+ //\r
+ // This example does not implement worker functions for the NV accessor functions. Only a callback evaluator\r
+ //\r
+ FPCallbackInfo.Signature = EFI_FP_CALLBACK_DATA_SIGNATURE;\r
+ FPCallbackInfo.DevMgrCallback.NvRead = NULL;\r
+ FPCallbackInfo.DevMgrCallback.NvWrite = NULL;\r
+ FPCallbackInfo.DevMgrCallback.Callback = DeviceManagerCallbackRoutine;\r
+\r
+ //\r
+ // Install protocol interface\r
+ //\r
+ FPCallbackInfo.CallbackHandle = NULL;\r
+\r
+ Status = gBS->InstallProtocolInterface (\r
+ &FPCallbackInfo.CallbackHandle,\r
+ &gEfiFormCallbackProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &FPCallbackInfo.DevMgrCallback\r
+ );\r
+\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Flag update pending in FormSet\r
+ //\r
+ UpdateData->FormSetUpdate = TRUE;\r
+ //\r
+ // Register CallbackHandle data for FormSet\r
+ //\r
+ UpdateData->FormCallbackHandle = (EFI_PHYSICAL_ADDRESS) (UINTN) FPCallbackInfo.CallbackHandle;\r
+ //\r
+ // Simply registering the callback handle\r
+ //\r
+ Hii->UpdateForm (Hii, FPCallbackInfo.DevMgrHiiHandle, (EFI_FORM_LABEL) 0x0000, TRUE, UpdateData);\r
+\r
+ FreePool (UpdateData);\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+CallDeviceManager (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Call the browser and display the device manager\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+ EFI_SUCCESS - Operation is successful.\r
+ EFI_INVALID_PARAMETER - If the inputs to SendForm function is not valid.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BufferSize;\r
+ UINTN Count;\r
+ EFI_HII_HANDLE Index;\r
+ UINT8 *Buffer;\r
+ EFI_IFR_FORM_SET *FormSetData;\r
+ CHAR16 *String;\r
+ UINTN StringLength;\r
+ EFI_HII_UPDATE_DATA *UpdateData;\r
+ STRING_REF Token;\r
+ STRING_REF TokenHelp;\r
+ IFR_OPTION *IfrOptionList;\r
+ UINT8 *VideoOption;\r
+ UINTN VideoOptionSize;\r
+ EFI_HII_HANDLE *HiiHandles;\r
+ UINT16 HandleBufferLength;\r
+ BOOLEAN BootDeviceMngrMenuResetRequired;\r
+\r
+ IfrOptionList = NULL;\r
+ VideoOption = NULL;\r
+ HiiHandles = NULL;\r
+ HandleBufferLength = 0;\r
+\r
+ //\r
+ // Connect all prior to entering the platform setup menu.\r
+ //\r
+ if (!gConnectAllHappened) {\r
+ BdsLibConnectAllDriversToAllControllers ();\r
+ gConnectAllHappened = TRUE;\r
+ }\r
+ //\r
+ // Allocate space for creation of UpdateData Buffer\r
+ //\r
+ UpdateData = AllocateZeroPool (0x1000);\r
+ ASSERT (UpdateData != NULL);\r
+\r
+ Status = EFI_SUCCESS;\r
+ Buffer = NULL;\r
+ FormSetData = NULL;\r
+ gCallbackKey = 0;\r
+ if (mTokenCount == 0) {\r
+ Hii->NewString (Hii, NULL, FPCallbackInfo.DevMgrHiiHandle, &mTokenCount, L" ");\r
+ }\r
+\r
+ Token = mTokenCount;\r
+ TokenHelp = (UINT16) (Token + 1);\r
+\r
+ //\r
+ // Reset the menu\r
+ //\r
+ for (Index = 0, Count = 1; Count < 0x10000; Count <<= 1, Index++) {\r
+ //\r
+ // We will strip off all previous menu entries\r
+ //\r
+ UpdateData->DataCount = 0xFF;\r
+\r
+ //\r
+ // Erase entries on this label\r
+ //\r
+ Hii->UpdateForm (Hii, FPCallbackInfo.DevMgrHiiHandle, (EFI_FORM_LABEL) Count, FALSE, UpdateData);\r
+\r
+ //\r
+ // Did we reach the end of the Token Table?\r
+ //\r
+ if (gStringTokenTable[Index] == 0xFFFF) {\r
+ break;\r
+ }\r
+\r
+ CreateSubTitleOpCode (gStringTokenTable[Index], &UpdateData->Data);\r
+ //\r
+ // Add a single menu item - in this case a subtitle for the device type\r
+ //\r
+ UpdateData->DataCount = 1;\r
+\r
+ //\r
+ // Add default title for this label\r
+ //\r
+ Hii->UpdateForm (Hii, FPCallbackInfo.DevMgrHiiHandle, (EFI_FORM_LABEL) Count, TRUE, UpdateData);\r
+ }\r
+ //\r
+ // Add a space and an exit string. Remember since we add things at the label and push other things beyond the\r
+ // label down, we add this in reverse order\r
+ //\r
+ CreateSubTitleOpCode (STRING_TOKEN (STR_EXIT_STRING), &UpdateData->Data);\r
+ Hii->UpdateForm (Hii, FPCallbackInfo.DevMgrHiiHandle, (EFI_FORM_LABEL) Count, TRUE, UpdateData);\r
+ CreateSubTitleOpCode (STR_EMPTY_STRING, &UpdateData->Data);\r
+ Hii->UpdateForm (Hii, FPCallbackInfo.DevMgrHiiHandle, (EFI_FORM_LABEL) Count, TRUE, UpdateData);\r
+\r
+ //\r
+ // Get all the Hii handles\r
+ //\r
+ Status = BdsLibGetHiiHandles (Hii, &HandleBufferLength, &HiiHandles);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ for (Index = 1, BufferSize = 0; Index < HandleBufferLength; Index++) {\r
+ //\r
+ // Am not initializing Buffer since the first thing checked is the size\r
+ // this way I can get the real buffersize in the smallest code size\r
+ //\r
+ Status = Hii->GetForms (Hii, Index, 0, &BufferSize, Buffer);\r
+\r
+ if (Status != EFI_NOT_FOUND) {\r
+ //\r
+ // BufferSize should have the real size of the forms now\r
+ //\r
+ Buffer = AllocateZeroPool (BufferSize);\r
+ ASSERT (Buffer != NULL);\r
+\r
+ //\r
+ // Am not initializing Buffer since the first thing checked is the size\r
+ // this way I can get the real buffersize in the smallest code size\r
+ //\r
+ Status = Hii->GetForms (Hii, Index, 0, &BufferSize, Buffer);\r
+\r
+ //\r
+ // Skip EFI_HII_PACK_HEADER, advance to EFI_IFR_FORM_SET data.\r
+ //\r
+ FormSetData = (EFI_IFR_FORM_SET *) (Buffer + sizeof (EFI_HII_PACK_HEADER));\r
+\r
+ //\r
+ // If this formset belongs in the device manager, add it to the menu\r
+ //\r
+ if (FormSetData->Class != EFI_NON_DEVICE_CLASS) {\r
+\r
+ StringLength = 0x1000;\r
+ String = AllocateZeroPool (StringLength);\r
+ ASSERT (String != NULL);\r
+\r
+ Status = Hii->GetString (Hii, Index, FormSetData->FormSetTitle, TRUE, NULL, &StringLength, String);\r
+ Status = Hii->NewString (Hii, NULL, FPCallbackInfo.DevMgrHiiHandle, &Token, String);\r
+\r
+ //\r
+ // If token value exceeded real token value - we need to add a new token values\r
+ //\r
+ if (Status == EFI_INVALID_PARAMETER) {\r
+ Token = 0;\r
+ TokenHelp = 0;\r
+ Status = Hii->NewString (Hii, NULL, FPCallbackInfo.DevMgrHiiHandle, &Token, String);\r
+ }\r
+\r
+ StringLength = 0x1000;\r
+ if (FormSetData->Help == 0) {\r
+ TokenHelp = 0;\r
+ } else {\r
+ Status = Hii->GetString (Hii, Index, FormSetData->Help, TRUE, NULL, &StringLength, String);\r
+ if (StringLength == 0x02) {\r
+ TokenHelp = 0;\r
+ } else {\r
+ Status = Hii->NewString (Hii, NULL, FPCallbackInfo.DevMgrHiiHandle, &TokenHelp, String);\r
+ if (Status == EFI_INVALID_PARAMETER) {\r
+ TokenHelp = 0;\r
+ Status = Hii->NewString (Hii, NULL, FPCallbackInfo.DevMgrHiiHandle, &TokenHelp, String);\r
+ }\r
+ }\r
+ }\r
+\r
+ FreePool (String);\r
+\r
+ CreateGotoOpCode (\r
+ 0x1000, // Device Manager Page\r
+ Token, // Description String Token\r
+ TokenHelp, // Description Help String Token\r
+ EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, // Flag designating callback is active\r
+ (UINT16) Index, // Callback key value\r
+ &UpdateData->Data // Buffer to fill with op-code\r
+ );\r
+\r
+ //\r
+ // In the off-chance that we have lots of extra tokens allocated to the DeviceManager\r
+ // this ensures we are fairly re-using the tokens instead of constantly growing the token\r
+ // storage for this one handle. If we incremented the token value beyond what it normally\r
+ // would use, we will fall back into the error path which seeds the token value with a 0\r
+ // so that we can correctly add a token value.\r
+ //\r
+ if (TokenHelp == 0) {\r
+ //\r
+ // Since we didn't add help, only advance Token by 1\r
+ //\r
+ Token++;\r
+ } else {\r
+ Token = (UINT16) (Token + 2);\r
+ TokenHelp = (UINT16) (TokenHelp + 2);\r
+ }\r
+ //\r
+ // This for loop basically will take the Class value which is a bitmask and\r
+ // update the form for every active bit. There will be a label at each bit\r
+ // location. So if someone had a device which a class of EFI_DISK_DEVICE_CLASS |\r
+ // EFI_ON_BOARD_DEVICE_CLASS, this routine will unwind that mask and drop the menu entry\r
+ // on each corresponding label.\r
+ //\r
+ for (Count = 1; Count < 0x10000; Count <<= 1) {\r
+ //\r
+ // This is an active bit, so update the form\r
+ //\r
+ if (FormSetData->Class & Count) {\r
+ Hii->UpdateForm (\r
+ Hii,\r
+ FPCallbackInfo.DevMgrHiiHandle,\r
+ (EFI_FORM_LABEL) (FormSetData->Class & Count),\r
+ TRUE,\r
+ UpdateData\r
+ );\r
+ }\r
+ }\r
+ }\r
+\r
+ BufferSize = 0;\r
+ //\r
+ // Reset Buffer pointer to original location\r
+ //\r
+ FreePool (Buffer);\r
+ }\r
+ }\r
+ //\r
+ // Add oneof for video BIOS selection\r
+ //\r
+ VideoOption = BdsLibGetVariableAndSize (\r
+ L"VBIOS",\r
+ &gEfiGenericPlatformVariableGuid,\r
+ &VideoOptionSize\r
+ );\r
+ if (NULL == VideoOption) {\r
+ FPCallbackInfo.Data.VideoBIOS = 0;\r
+ } else {\r
+ FPCallbackInfo.Data.VideoBIOS = VideoOption[0];\r
+ FreePool (VideoOption);\r
+ }\r
+\r
+ ASSERT (FPCallbackInfo.Data.VideoBIOS <= 1);\r
+\r
+ IfrOptionList = AllocatePool (2 * sizeof (IFR_OPTION));\r
+ if (IfrOptionList != NULL) {\r
+ IfrOptionList[0].Flags = EFI_IFR_FLAG_INTERACTIVE;\r
+ IfrOptionList[0].Key = SET_VIDEO_BIOS_TYPE_QUESTION_ID + 0x2000;\r
+ IfrOptionList[0].StringToken = STRING_TOKEN (STR_ONE_OF_PCI);\r
+ IfrOptionList[0].Value = 0;\r
+ IfrOptionList[0].OptionString = NULL;\r
+ IfrOptionList[1].Flags = EFI_IFR_FLAG_INTERACTIVE;\r
+ IfrOptionList[1].Key = SET_VIDEO_BIOS_TYPE_QUESTION_ID + 0x2000;\r
+ IfrOptionList[1].StringToken = STRING_TOKEN (STR_ONE_OF_AGP);\r
+ IfrOptionList[1].Value = 1;\r
+ IfrOptionList[1].OptionString = NULL;\r
+ IfrOptionList[FPCallbackInfo.Data.VideoBIOS].Flags |= EFI_IFR_FLAG_DEFAULT;\r
+\r
+ CreateOneOfOpCode (\r
+ SET_VIDEO_BIOS_TYPE_QUESTION_ID,\r
+ (UINT8) 1,\r
+ STRING_TOKEN (STR_ONE_OF_VBIOS),\r
+ STRING_TOKEN (STR_ONE_OF_VBIOS_HELP),\r
+ IfrOptionList,\r
+ 2,\r
+ &UpdateData->Data\r
+ );\r
+\r
+ UpdateData->DataCount = 4;\r
+ Hii->UpdateForm (Hii, FPCallbackInfo.DevMgrHiiHandle, (EFI_FORM_LABEL) EFI_VBIOS_CLASS, TRUE, UpdateData);\r
+ FreePool (IfrOptionList);\r
+ }\r
+\r
+ BootDeviceMngrMenuResetRequired = FALSE;\r
+ Status = gBrowser->SendForm (\r
+ gBrowser,\r
+ TRUE, // Use the database\r
+ &FPCallbackInfo.DevMgrHiiHandle, // The HII Handle\r
+ 1,\r
+ NULL,\r
+ FPCallbackInfo.CallbackHandle,\r
+ (UINT8 *) &FPCallbackInfo.Data,\r
+ NULL,\r
+ &BootDeviceMngrMenuResetRequired\r
+ );\r
+\r
+ if (BootDeviceMngrMenuResetRequired) {\r
+ EnableResetRequired ();\r
+ }\r
+\r
+ Hii->ResetStrings (Hii, FPCallbackInfo.DevMgrHiiHandle);\r
+\r
+ //\r
+ // We will have returned from processing a callback - user either hit ESC to exit, or selected\r
+ // a target to display\r
+ //\r
+ if (gCallbackKey != 0 && gCallbackKey < 0x2000) {\r
+ BootDeviceMngrMenuResetRequired = FALSE;\r
+ Status = gBrowser->SendForm (\r
+ gBrowser,\r
+ TRUE, // Use the database\r
+ (EFI_HII_HANDLE *) &gCallbackKey, // The HII Handle\r
+ 1,\r
+ NULL,\r
+ NULL, // This is the handle that the interface to the callback was installed on\r
+ NULL,\r
+ NULL,\r
+ &BootDeviceMngrMenuResetRequired\r
+ );\r
+\r
+ if (BootDeviceMngrMenuResetRequired) {\r
+ EnableResetRequired ();\r
+ }\r
+ //\r
+ // Force return to Device Manager\r
+ //\r
+ gCallbackKey = 4;\r
+ }\r
+\r
+ if (gCallbackKey >= 0x2000) {\r
+ gCallbackKey = 4;\r
+ }\r
+\r
+ FreePool (UpdateData);\r
+ FreePool (HiiHandles);\r
+\r
+ return Status;\r
+}\r