--- /dev/null
+/** @file\r
+ Emu Bus driver\r
+\r
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+Portions copyright (c) 2011, Apple Inc. All rights reserved.\r
+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
+\r
+**/\r
+\r
+#include "EmuBusDriverDxe.h"\r
+\r
+\r
+\r
+//\r
+// DriverBinding protocol global\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gEmuBusDriverBinding = {\r
+ EmuBusDriverBindingSupported,\r
+ EmuBusDriverBindingStart,\r
+ EmuBusDriverBindingStop,\r
+ 0xa,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+EmuBusDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ EMU_THUNK_PROTOCOL *EmuThunk;\r
+\r
+ //\r
+ // Check the contents of the first Device Path Node of RemainingDevicePath to make sure\r
+ // it is a legal Device Path Node for this bus driver's children.\r
+ //\r
+ if (RemainingDevicePath != NULL) {\r
+ //\r
+ // Check if RemainingDevicePath is the End of Device Path Node, \r
+ // if yes, go on checking other conditions\r
+ //\r
+ if (!IsDevicePathEnd (RemainingDevicePath)) {\r
+ //\r
+ // If RemainingDevicePath isn't the End of Device Path Node,\r
+ // check its validation\r
+ //\r
+ if (RemainingDevicePath->Type != HARDWARE_DEVICE_PATH ||\r
+ RemainingDevicePath->SubType != HW_VENDOR_DP ||\r
+ DevicePathNodeLength(RemainingDevicePath) != sizeof(EMU_VENDOR_DEVICE_PATH_NODE)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Open the IO Abstraction(s) needed to perform the supported test\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEmuThunkProtocolGuid,\r
+ (VOID **)&EmuThunk ,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Close the I/O Abstraction(s) used to perform the supported test\r
+ //\r
+ gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEmuThunkProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+\r
+ //\r
+ // Open the EFI Device Path protocol needed to perform the supported test\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **)&ParentDevicePath,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+\r
+ //\r
+ // Close protocol, don't use device path protocol in the Support() function\r
+ //\r
+ gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+EmuBusDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STATUS InstallStatus;\r
+ EMU_THUNK_PROTOCOL *EmuThunk;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ EMU_IO_DEVICE *EmuDevice;\r
+ EMU_BUS_DEVICE *EmuBusDevice;\r
+ EMU_IO_THUNK_PROTOCOL *EmuIoThunk;\r
+ UINT16 ComponentName[512];\r
+ EMU_VENDOR_DEVICE_PATH_NODE *Node;\r
+ BOOLEAN CreateDevice;\r
+\r
+ InstallStatus = EFI_UNSUPPORTED;\r
+ Status = EFI_UNSUPPORTED;\r
+\r
+ //\r
+ // Grab the protocols we need\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **)&ParentDevicePath,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEmuThunkProtocolGuid,\r
+ (VOID **)&EmuThunk,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
+ return Status;\r
+ }\r
+\r
+ if (Status != EFI_ALREADY_STARTED) {\r
+ EmuBusDevice = AllocatePool (sizeof (EMU_BUS_DEVICE));\r
+ if (EmuBusDevice == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ EmuBusDevice->Signature = EMU_BUS_DEVICE_SIGNATURE;\r
+ EmuBusDevice->ControllerNameTable = NULL;\r
+\r
+ AddUnicodeString2 (\r
+ "eng",\r
+ gEmuBusDriverComponentName.SupportedLanguages,\r
+ &EmuBusDevice->ControllerNameTable,\r
+ L"Emulator Bus Controller",\r
+ TRUE\r
+ );\r
+ AddUnicodeString2 (\r
+ "en",\r
+ gEmuBusDriverComponentName2.SupportedLanguages,\r
+ &EmuBusDevice->ControllerNameTable,\r
+ L"Emulator Bus Controller",\r
+ FALSE\r
+ );\r
+\r
+\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &ControllerHandle,\r
+ &gEfiCallerIdGuid, EmuBusDevice,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreeUnicodeStringTable (EmuBusDevice->ControllerNameTable);\r
+ gBS->FreePool (EmuBusDevice);\r
+ return Status;\r
+ }\r
+ }\r
+\r
+\r
+ for (Status = EFI_SUCCESS, EmuIoThunk = NULL; !EFI_ERROR (Status); ) {\r
+ Status = EmuThunk->GetNextProtocol (TRUE, &EmuIoThunk);\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ CreateDevice = TRUE;\r
+ if (RemainingDevicePath != NULL) {\r
+ CreateDevice = FALSE;\r
+ //\r
+ // Check if RemainingDevicePath is the End of Device Path Node, \r
+ // if yes, don't create any child device \r
+ //\r
+ if (!IsDevicePathEnd (RemainingDevicePath)) {\r
+ //\r
+ // If RemainingDevicePath isn't the End of Device Path Node,\r
+ // check its validation\r
+ //\r
+ Node = (EMU_VENDOR_DEVICE_PATH_NODE *) RemainingDevicePath;\r
+ if (Node->VendorDevicePath.Header.Type == HARDWARE_DEVICE_PATH &&\r
+ Node->VendorDevicePath.Header.SubType == HW_VENDOR_DP &&\r
+ DevicePathNodeLength (&Node->VendorDevicePath.Header) == sizeof (EMU_VENDOR_DEVICE_PATH_NODE)\r
+ ) {\r
+ if (CompareGuid (&Node->VendorDevicePath.Guid, EmuIoThunk->Protocol) && Node->Instance == EmuIoThunk->Instance) {\r
+ CreateDevice = TRUE;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if (CreateDevice) {\r
+ //\r
+ // Allocate instance structure, and fill in parent information.\r
+ //\r
+ EmuDevice = AllocatePool (sizeof (EMU_IO_DEVICE));\r
+ if (EmuDevice == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ EmuDevice->Handle = NULL;\r
+ EmuDevice->ControllerHandle = ControllerHandle;\r
+ EmuDevice->ParentDevicePath = ParentDevicePath;\r
+ CopyMem (&EmuDevice->EmuIoThunk, EmuIoThunk, sizeof (EMU_IO_THUNK_PROTOCOL));\r
+ \r
+ EmuDevice->ControllerNameTable = NULL;\r
+\r
+ StrnCpy (ComponentName, EmuIoThunk->ConfigString, sizeof (ComponentName)/sizeof (CHAR16));\r
+\r
+ EmuDevice->DevicePath = EmuBusCreateDevicePath (\r
+ ParentDevicePath,\r
+ EmuIoThunk->Protocol,\r
+ EmuIoThunk->Instance\r
+ );\r
+ if (EmuDevice->DevicePath == NULL) {\r
+ gBS->FreePool (EmuDevice);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ AddUnicodeString (\r
+ "eng",\r
+ gEmuBusDriverComponentName.SupportedLanguages,\r
+ &EmuDevice->ControllerNameTable,\r
+ ComponentName\r
+ );\r
+\r
+ EmuDevice->Signature = EMU_IO_DEVICE_SIGNATURE;\r
+\r
+ InstallStatus = gBS->InstallMultipleProtocolInterfaces (\r
+ &EmuDevice->Handle,\r
+ &gEfiDevicePathProtocolGuid, EmuDevice->DevicePath,\r
+ &gEmuIoThunkProtocolGuid, &EmuDevice->EmuIoThunk,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (InstallStatus)) {\r
+ FreeUnicodeStringTable (EmuDevice->ControllerNameTable);\r
+ gBS->FreePool (EmuDevice);\r
+ } else {\r
+ //\r
+ // Open For Child Device\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEmuThunkProtocolGuid,\r
+ (VOID **)&EmuThunk ,\r
+ This->DriverBindingHandle,\r
+ EmuDevice->Handle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ InstallStatus = EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return InstallStatus;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+EmuBusDriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ BOOLEAN AllChildrenStopped;\r
+ EMU_IO_THUNK_PROTOCOL *EmuIoThunk;\r
+ EMU_BUS_DEVICE *EmuBusDevice;\r
+ EMU_IO_DEVICE *EmuDevice;\r
+ EMU_THUNK_PROTOCOL *EmuThunk;\r
+\r
+ //\r
+ // Complete all outstanding transactions to Controller.\r
+ // Don't allow any new transaction to Controller to be started.\r
+ //\r
+\r
+ if (NumberOfChildren == 0) {\r
+ //\r
+ // Close the bus driver\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiCallerIdGuid,\r
+ (VOID **)&EmuBusDevice,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ ControllerHandle,\r
+ &gEfiCallerIdGuid, EmuBusDevice,\r
+ NULL\r
+ );\r
+\r
+ FreeUnicodeStringTable (EmuBusDevice->ControllerNameTable);\r
+\r
+ gBS->FreePool (EmuBusDevice);\r
+\r
+ gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEmuThunkProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+\r
+ gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ AllChildrenStopped = TRUE;\r
+\r
+ for (Index = 0; Index < NumberOfChildren; Index++) {\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandleBuffer[Index],\r
+ &gEmuIoThunkProtocolGuid,\r
+ (VOID **)&EmuIoThunk,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ EmuDevice = EMU_IO_DEVICE_FROM_THIS (EmuIoThunk);\r
+\r
+ Status = gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEmuThunkProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ EmuDevice->Handle\r
+ );\r
+\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ EmuDevice->Handle,\r
+ &gEfiDevicePathProtocolGuid, EmuDevice->DevicePath,\r
+ &gEmuIoThunkProtocolGuid, EmuDevice->EmuIoThunk,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEmuThunkProtocolGuid,\r
+ (VOID **) &EmuThunk ,\r
+ This->DriverBindingHandle,\r
+ EmuDevice->Handle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ } else {\r
+ //\r
+ // Close the child handle\r
+ //\r
+ FreeUnicodeStringTable (EmuDevice->ControllerNameTable);\r
+ FreePool (EmuDevice);\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ AllChildrenStopped = FALSE;\r
+ }\r
+ }\r
+\r
+ if (!AllChildrenStopped) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+ Create a device path node using Guid and InstanceNumber and append it to\r
+ the passed in RootDevicePath\r
+\r
+Arguments:\r
+ RootDevicePath - Root of the device path to return.\r
+\r
+ Guid - GUID to use in vendor device path node.\r
+\r
+ InstanceNumber - Instance number to use in the vendor device path. This\r
+ argument is needed to make sure each device path is unique.\r
+\r
+Returns:\r
+\r
+ EFI_DEVICE_PATH_PROTOCOL \r
+\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+EmuBusCreateDevicePath (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RootDevicePath,\r
+ IN EFI_GUID *Guid,\r
+ IN UINT16 InstanceNumber\r
+ )\r
+{\r
+ EMU_VENDOR_DEVICE_PATH_NODE DevicePath;\r
+\r
+ DevicePath.VendorDevicePath.Header.Type = HARDWARE_DEVICE_PATH;\r
+ DevicePath.VendorDevicePath.Header.SubType = HW_VENDOR_DP;\r
+ SetDevicePathNodeLength (&DevicePath.VendorDevicePath.Header, sizeof (EMU_VENDOR_DEVICE_PATH_NODE));\r
+\r
+ //\r
+ // The GUID defines the Class\r
+ //\r
+ CopyMem (&DevicePath.VendorDevicePath.Guid, Guid, sizeof (EFI_GUID));\r
+\r
+ //\r
+ // Add an instance number so we can make sure there are no Device Path\r
+ // duplication.\r
+ //\r
+ DevicePath.Instance = InstanceNumber;\r
+\r
+ return AppendDevicePathNode (\r
+ RootDevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *) &DevicePath\r
+ );\r
+}\r
+\r
+\r
+\r
+/**\r
+ The user Entry Point for module EmuBusDriver. The user code starts with this function.\r
+\r
+ @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
+ @param[in] SystemTable A pointer to the EFI System Table.\r
+ \r
+ @retval EFI_SUCCESS The entry point is executed successfully.\r
+ @retval other Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeEmuBusDriver (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = EfiLibInstallAllDriverProtocols (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gEmuBusDriverBinding,\r
+ ImageHandle,\r
+ &gEmuBusDriverComponentName,\r
+ NULL,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+\r
+\r