/** @file | |
Copyright (C) 2016, Linaro Ltd. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "NonDiscoverablePciDeviceIo.h" | |
#include <Protocol/DriverBinding.h> | |
#define MAX_NON_DISCOVERABLE_PCI_DEVICE_ID (32 * 256) | |
STATIC UINTN mUniqueIdCounter = 0; | |
EFI_CPU_ARCH_PROTOCOL *mCpu; | |
// | |
// We only support the following device types | |
// | |
STATIC | |
CONST EFI_GUID *CONST | |
SupportedNonDiscoverableDevices[] = { | |
&gEdkiiNonDiscoverableAhciDeviceGuid, | |
&gEdkiiNonDiscoverableEhciDeviceGuid, | |
&gEdkiiNonDiscoverableNvmeDeviceGuid, | |
&gEdkiiNonDiscoverableOhciDeviceGuid, | |
&gEdkiiNonDiscoverableSdhciDeviceGuid, | |
&gEdkiiNonDiscoverableUfsDeviceGuid, | |
&gEdkiiNonDiscoverableUhciDeviceGuid, | |
&gEdkiiNonDiscoverableXhciDeviceGuid, | |
}; | |
// | |
// Probe, start and stop functions of this driver, called by the DXE core for | |
// specific devices. | |
// | |
// The following specifications document these interfaces: | |
// - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol | |
// - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol | |
// | |
// The implementation follows: | |
// - Driver Writer's Guide for UEFI 2.3.1 v1.01 | |
// - 5.1.3.4 OpenProtocol() and CloseProtocol() | |
// - UEFI Spec 2.3.1 + Errata C | |
// - 6.3 Protocol Handler Services | |
// | |
/** | |
Supported function of Driver Binding protocol for this driver. | |
Test to see if this driver supports ControllerHandle. | |
@param This Protocol instance pointer. | |
@param DeviceHandle Handle of device to test. | |
@param RemainingDevicePath A pointer to the device path. | |
it should be ignored by device driver. | |
@retval EFI_SUCCESS This driver supports this device. | |
@retval other This driver does not support this device. | |
**/ | |
STATIC | |
EFI_STATUS | |
EFIAPI | |
NonDiscoverablePciDeviceSupported ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE DeviceHandle, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
) | |
{ | |
NON_DISCOVERABLE_DEVICE *Device; | |
EFI_STATUS Status; | |
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc; | |
INTN Idx; | |
Status = gBS->OpenProtocol ( | |
DeviceHandle, | |
&gEdkiiNonDiscoverableDeviceProtocolGuid, | |
(VOID **)&Device, | |
This->DriverBindingHandle, | |
DeviceHandle, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = EFI_UNSUPPORTED; | |
for (Idx = 0; Idx < ARRAY_SIZE (SupportedNonDiscoverableDevices); Idx++) { | |
if (CompareGuid (Device->Type, SupportedNonDiscoverableDevices[Idx])) { | |
Status = EFI_SUCCESS; | |
break; | |
} | |
} | |
if (EFI_ERROR (Status)) { | |
goto CloseProtocol; | |
} | |
// | |
// We only support MMIO devices, so iterate over the resources to ensure | |
// that they only describe things that we can handle | |
// | |
for (Desc = Device->Resources; Desc->Desc != ACPI_END_TAG_DESCRIPTOR; | |
Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) | |
{ | |
if ((Desc->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) || | |
(Desc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM)) | |
{ | |
Status = EFI_UNSUPPORTED; | |
break; | |
} | |
} | |
CloseProtocol: | |
gBS->CloseProtocol ( | |
DeviceHandle, | |
&gEdkiiNonDiscoverableDeviceProtocolGuid, | |
This->DriverBindingHandle, | |
DeviceHandle | |
); | |
return Status; | |
} | |
/** | |
This routine is called right after the .Supported() called and | |
Start this driver on ControllerHandle. | |
@param This Protocol instance pointer. | |
@param DeviceHandle Handle of device to bind driver to. | |
@param RemainingDevicePath A pointer to the device path. | |
it should be ignored by device driver. | |
@retval EFI_SUCCESS This driver is added to this device. | |
@retval other Some error occurs when binding this driver to this device. | |
**/ | |
STATIC | |
EFI_STATUS | |
EFIAPI | |
NonDiscoverablePciDeviceStart ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE DeviceHandle, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
) | |
{ | |
NON_DISCOVERABLE_PCI_DEVICE *Dev; | |
EFI_STATUS Status; | |
ASSERT (mUniqueIdCounter < MAX_NON_DISCOVERABLE_PCI_DEVICE_ID); | |
if (mUniqueIdCounter >= MAX_NON_DISCOVERABLE_PCI_DEVICE_ID) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Dev = AllocateZeroPool (sizeof *Dev); | |
if (Dev == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Status = gBS->OpenProtocol ( | |
DeviceHandle, | |
&gEdkiiNonDiscoverableDeviceProtocolGuid, | |
(VOID **)&Dev->Device, | |
This->DriverBindingHandle, | |
DeviceHandle, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (EFI_ERROR (Status)) { | |
goto FreeDev; | |
} | |
InitializePciIoProtocol (Dev); | |
// | |
// Setup complete, attempt to export the driver instance's | |
// EFI_PCI_IO_PROTOCOL interface. | |
// | |
Dev->Signature = NON_DISCOVERABLE_PCI_DEVICE_SIG; | |
Status = gBS->InstallProtocolInterface ( | |
&DeviceHandle, | |
&gEfiPciIoProtocolGuid, | |
EFI_NATIVE_INTERFACE, | |
&Dev->PciIo | |
); | |
if (EFI_ERROR (Status)) { | |
goto CloseProtocol; | |
} | |
Dev->UniqueId = mUniqueIdCounter++; | |
return EFI_SUCCESS; | |
CloseProtocol: | |
gBS->CloseProtocol ( | |
DeviceHandle, | |
&gEdkiiNonDiscoverableDeviceProtocolGuid, | |
This->DriverBindingHandle, | |
DeviceHandle | |
); | |
FreeDev: | |
FreePool (Dev); | |
return Status; | |
} | |
/** | |
Stop this driver on ControllerHandle. | |
@param This Protocol instance pointer. | |
@param DeviceHandle Handle of device to stop driver on. | |
@param NumberOfChildren Not used. | |
@param ChildHandleBuffer Not used. | |
@retval EFI_SUCCESS This driver is removed from this device. | |
@retval other Some error occurs when removing this driver from this device. | |
**/ | |
STATIC | |
EFI_STATUS | |
EFIAPI | |
NonDiscoverablePciDeviceStop ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE DeviceHandle, | |
IN UINTN NumberOfChildren, | |
IN EFI_HANDLE *ChildHandleBuffer | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_PCI_IO_PROTOCOL *PciIo; | |
NON_DISCOVERABLE_PCI_DEVICE *Dev; | |
Status = gBS->OpenProtocol ( | |
DeviceHandle, | |
&gEfiPciIoProtocolGuid, | |
(VOID **)&PciIo, | |
This->DriverBindingHandle, | |
DeviceHandle, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO (PciIo); | |
// | |
// Handle Stop() requests for in-use driver instances gracefully. | |
// | |
Status = gBS->UninstallProtocolInterface ( | |
DeviceHandle, | |
&gEfiPciIoProtocolGuid, | |
&Dev->PciIo | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
gBS->CloseProtocol ( | |
DeviceHandle, | |
&gEdkiiNonDiscoverableDeviceProtocolGuid, | |
This->DriverBindingHandle, | |
DeviceHandle | |
); | |
FreePool (Dev); | |
return EFI_SUCCESS; | |
} | |
// | |
// The static object that groups the Supported() (ie. probe), Start() and | |
// Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata | |
// C, 10.1 EFI Driver Binding Protocol. | |
// | |
STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = { | |
&NonDiscoverablePciDeviceSupported, | |
&NonDiscoverablePciDeviceStart, | |
&NonDiscoverablePciDeviceStop, | |
0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers | |
NULL, | |
NULL | |
}; | |
/** | |
Entry point of this driver. | |
@param ImageHandle Image handle this driver. | |
@param SystemTable Pointer to the System Table. | |
@retval EFI_SUCCESS The entry point is executed successfully. | |
@retval other Some error occurred when executing this entry point. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
NonDiscoverablePciDeviceDxeEntryPoint ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
EFI_STATUS Status; | |
Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mCpu); | |
ASSERT_EFI_ERROR (Status); | |
return EfiLibInstallDriverBindingComponentName2 ( | |
ImageHandle, | |
SystemTable, | |
&gDriverBinding, | |
ImageHandle, | |
&gComponentName, | |
&gComponentName2 | |
); | |
} |