+/** @file\r
+ Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>\r
+\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
+#include <PiDxe.h>\r
+\r
+#include <Guid/NonDiscoverableDevice.h>\r
+\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/NonDiscoverableDeviceRegistrationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/NonDiscoverableDevice.h>\r
+\r
+STATIC\r
+CONST EFI_GUID *\r
+GetGuidFromType (\r
+ IN NON_DISCOVERABLE_DEVICE_TYPE Type\r
+ )\r
+{\r
+ switch (Type) {\r
+ case NonDiscoverableDeviceTypeAhci:\r
+ return &gEdkiiNonDiscoverableAhciDeviceGuid;\r
+\r
+ case NonDiscoverableDeviceTypeAmba:\r
+ return &gEdkiiNonDiscoverableAmbaDeviceGuid;\r
+\r
+ case NonDiscoverableDeviceTypeEhci:\r
+ return &gEdkiiNonDiscoverableEhciDeviceGuid;\r
+\r
+ case NonDiscoverableDeviceTypeNvme:\r
+ return &gEdkiiNonDiscoverableNvmeDeviceGuid;\r
+\r
+ case NonDiscoverableDeviceTypeOhci:\r
+ return &gEdkiiNonDiscoverableOhciDeviceGuid;\r
+\r
+ case NonDiscoverableDeviceTypeSdhci:\r
+ return &gEdkiiNonDiscoverableSdhciDeviceGuid;\r
+\r
+ case NonDiscoverableDeviceTypeUfs:\r
+ return &gEdkiiNonDiscoverableUfsDeviceGuid;\r
+\r
+ case NonDiscoverableDeviceTypeUhci:\r
+ return &gEdkiiNonDiscoverableUhciDeviceGuid;\r
+\r
+ case NonDiscoverableDeviceTypeXhci:\r
+ return &gEdkiiNonDiscoverableXhciDeviceGuid;\r
+\r
+ default:\r
+ return NULL;\r
+ }\r
+}\r
+\r
+#pragma pack (1)\r
+typedef struct {\r
+ VENDOR_DEVICE_PATH Vendor;\r
+ UINT64 BaseAddress;\r
+ UINT8 ResourceType;\r
+ EFI_DEVICE_PATH_PROTOCOL End;\r
+} NON_DISCOVERABLE_DEVICE_PATH;\r
+#pragma pack ()\r
+\r
+/**\r
+ Register a non-discoverable MMIO device\r
+\r
+ @param[in] DeviceType The type of non-discoverable device\r
+ @param[in] DmaType Whether the device is DMA coherent\r
+ @param[in] InitFunc Initialization routine to be invoked when\r
+ the device is enabled\r
+ @param[in,out] Handle The handle onto which to install the\r
+ non-discoverable device protocol.\r
+ If Handle is NULL or *Handle is NULL, a\r
+ new handle will be allocated.\r
+ @param[in] NumMmioResources The number of UINTN base/size pairs that\r
+ follow, each describing an MMIO region\r
+ owned by the device\r
+\r
+ @retval EFI_SUCCESS The registration succeeded.\r
+ @retval EFI_INVALID_PARAMETER An invalid argument was given\r
+ @retval Other The registration failed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RegisterNonDiscoverableMmioDevice (\r
+ IN NON_DISCOVERABLE_DEVICE_TYPE Type,\r
+ IN NON_DISCOVERABLE_DEVICE_DMA_TYPE DmaType,\r
+ IN NON_DISCOVERABLE_DEVICE_INIT InitFunc,\r
+ IN OUT EFI_HANDLE *Handle OPTIONAL,\r
+ IN UINTN NumMmioResources,\r
+ ...\r
+ )\r
+{\r
+ NON_DISCOVERABLE_DEVICE *Device;\r
+ NON_DISCOVERABLE_DEVICE_PATH *DevicePath;\r
+ EFI_HANDLE LocalHandle;\r
+ EFI_STATUS Status;\r
+ UINTN AllocSize;\r
+ UINTN Index;\r
+ VA_LIST Args;\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;\r
+ EFI_ACPI_END_TAG_DESCRIPTOR *End;\r
+ UINTN Base, Size;\r
+\r
+ if (Type >= NonDiscoverableDeviceTypeMax ||\r
+ DmaType >= NonDiscoverableDeviceDmaTypeMax ||\r
+ NumMmioResources == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Handle == NULL) {\r
+ Handle = &LocalHandle;\r
+ LocalHandle = NULL;\r
+ }\r
+\r
+ AllocSize = sizeof *Device +\r
+ NumMmioResources * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) +\r
+ sizeof (EFI_ACPI_END_TAG_DESCRIPTOR);\r
+ Device = (NON_DISCOVERABLE_DEVICE *)AllocateZeroPool (AllocSize);\r
+ if (Device == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Device->Type = GetGuidFromType (Type);\r
+ ASSERT (Device->Type != NULL);\r
+\r
+ Device->DmaType = DmaType;\r
+ Device->Initialize = InitFunc;\r
+ Device->Resources = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(Device + 1);\r
+\r
+ VA_START (Args, NumMmioResources);\r
+ for (Index = 0; Index < NumMmioResources; Index++) {\r
+ Desc = &Device->Resources [Index];\r
+ Base = VA_ARG (Args, UINTN);\r
+ Size = VA_ARG (Args, UINTN);\r
+\r
+ Desc->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
+ Desc->Len = sizeof *Desc - 3;\r
+ Desc->AddrRangeMin = Base;\r
+ Desc->AddrLen = Size;\r
+ Desc->AddrRangeMax = Base + Size - 1;\r
+ Desc->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
+ Desc->AddrSpaceGranularity = (Base + Size > SIZE_4GB) ? 64 : 32;\r
+ Desc->AddrTranslationOffset = 0;\r
+ }\r
+ VA_END (Args);\r
+\r
+ End = (EFI_ACPI_END_TAG_DESCRIPTOR *)&Device->Resources [NumMmioResources];\r
+\r
+ End->Desc = ACPI_END_TAG_DESCRIPTOR;\r
+ End->Checksum = 0;\r
+\r
+ DevicePath = (NON_DISCOVERABLE_DEVICE_PATH *)CreateDeviceNode (\r
+ HARDWARE_DEVICE_PATH,\r
+ HW_VENDOR_DP,\r
+ sizeof (*DevicePath));\r
+ if (DevicePath == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto FreeDevice;\r
+ }\r
+\r
+ CopyGuid (&DevicePath->Vendor.Guid, &gEdkiiNonDiscoverableDeviceProtocolGuid);\r
+\r
+ //\r
+ // Use the base address and type of the first region to\r
+ // make the device path unique\r
+ //\r
+ DevicePath->BaseAddress = Device->Resources [0].AddrRangeMin;\r
+ DevicePath->ResourceType = Device->Resources [0].ResType;\r
+\r
+ SetDevicePathNodeLength (&DevicePath->Vendor,\r
+ sizeof (*DevicePath) - sizeof (DevicePath->End));\r
+ SetDevicePathEndNode (&DevicePath->End);\r
+\r
+ Status = gBS->InstallMultipleProtocolInterfaces (Handle,\r
+ &gEdkiiNonDiscoverableDeviceProtocolGuid, Device,\r
+ &gEfiDevicePathProtocolGuid, DevicePath,\r
+ NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ goto FreeDevicePath;\r
+ }\r
+ return EFI_SUCCESS;\r
+\r
+FreeDevicePath:\r
+ FreePool (DevicePath);\r
+\r
+FreeDevice:\r
+ FreePool (Device);\r
+\r
+ return Status;\r
+}\r