/** @file
Device driver for the ChaosKey hardware random number generator.
Copyright (c) 2016 - 2017, Linaro Ltd. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include "ChaosKeyDriver.h"
/**
Tests to see if this driver supports a given controller.
@param This[in] A pointer to the EFI_DRIVER_BINDING_PROTOCOL
instance.
@param ControllerHandle[in] The handle of the controller to test.
@param RemainingDevicePath[in] The remaining device path.
(Ignored - this is not a bus driver.)
@retval EFI_SUCCESS The driver supports this controller.
@retval EFI_ALREADY_STARTED The device specified by ControllerHandle is
already being managed by the driver specified
by This.
@retval EFI_UNSUPPORTED The device specified by ControllerHandle is
not supported by the driver specified by This.
**/
EFI_STATUS
EFIAPI
UsbHwrngDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_USB_DEVICE_DESCRIPTOR Device;
EFI_USB_IO_PROTOCOL *UsbIo;
EFI_STATUS Status;
//
// Connect to the USB stack
//
Status = gBS->OpenProtocol (ControllerHandle,
&gEfiUsbIoProtocolGuid,
(VOID **) &UsbIo,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get the interface descriptor to check the USB class and find a transport
// protocol handler.
//
Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &Device);
if (!EFI_ERROR (Status)) {
//
// Validate the adapter
//
if ((Device.IdVendor != CHAOSKEY_VENDOR_ID) ||
(Device.IdProduct != CHAOSKEY_PRODUCT_ID)) {
Status = EFI_UNSUPPORTED;
} else {
DEBUG ((DEBUG_INIT | DEBUG_INFO,
"Detected ChaosKey RNG device (USB VendorID:0x%04x ProductID:0x%04x)\n",
Device.IdVendor, Device.IdProduct));
Status = EFI_SUCCESS;
}
}
//
// Clean up.
//
gBS->CloseProtocol (ControllerHandle,
&gEfiUsbIoProtocolGuid,
This->DriverBindingHandle,
ControllerHandle);
return Status;
}
/**
Starts a device controller or a bus controller.
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
instance.
@param[in] ControllerHandle The handle of the device to start. This
handle must support a protocol interface that
supplies an I/O abstraction to the driver.
@param[in] RemainingDevicePath The remaining portion of the device path.
(Ignored - this is not a bus driver.)
@retval EFI_SUCCESS The device was started.
@retval EFI_DEVICE_ERROR The device could not be started due to a
device error.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
lack of resources.
**/
EFI_STATUS
EFIAPI
UsbHwrngDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
return ChaosKeyInit (This->DriverBindingHandle, ControllerHandle);
}
/**
Stops a device controller or a bus controller.
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
instance.
@param[in] ControllerHandle A handle to the device being stopped. The handle
must support a bus specific I/O protocol for the
driver to use to stop the device.
@param[in] NumberOfChildren The number of child device handles in
ChildHandleBuffer.
@param[in] ChildHandleBuffer An array of child handles to be freed. May be
NULL if NumberOfChildren is 0.
@retval EFI_SUCCESS The device was stopped.
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device
error.
**/
EFI_STATUS
EFIAPI
UsbHwrngDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
)
{
return ChaosKeyRelease (This->DriverBindingHandle, ControllerHandle);
}
STATIC
EFI_DRIVER_BINDING_PROTOCOL gUsbDriverBinding = {
UsbHwrngDriverBindingSupported,
UsbHwrngDriverBindingStart,
UsbHwrngDriverBindingStop,
0xa,
NULL,
NULL
};
/**
The entry point of ChaosKey UEFI Driver.
@param ImageHandle The image handle of the UEFI Driver.
@param SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The Driver or UEFI Driver exited normally.
@retval EFI_INCOMPATIBLE_VERSION _gUefiDriverRevision is greater than
SystemTable->Hdr.Revision.
**/
EFI_STATUS
EFIAPI
EntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// Add the driver to the list of drivers
//
Status = EfiLibInstallDriverBindingComponentName2 (
ImageHandle, SystemTable, &gUsbDriverBinding, ImageHandle,
NULL, &gChaosKeyDriverComponentName2);
ASSERT_EFI_ERROR (Status);
DEBUG ((DEBUG_INIT | DEBUG_INFO, "*** Installed ChaosKey driver! ***\n"));
return EFI_SUCCESS;
}
/**
Unload function for the ChaosKey Driver.
@param ImageHandle[in] The allocated handle for the EFI image
@retval EFI_SUCCESS The driver was unloaded successfully
@retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
**/
EFI_STATUS
EFIAPI
UnloadImage (
IN EFI_HANDLE ImageHandle
)
{
EFI_STATUS Status;
EFI_HANDLE *HandleBuffer;
UINTN HandleCount;
UINTN Index;
//
// Retrieve all USB I/O handles in the handle database
//
Status = gBS->LocateHandleBuffer (ByProtocol,
&gEfiUsbIoProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Disconnect the driver from the handles in the handle database
//
for (Index = 0; Index < HandleCount; Index++) {
Status = gBS->DisconnectController (HandleBuffer[Index],
gImageHandle,
NULL);
}
//
// Free the handle array
//
gBS->FreePool (HandleBuffer);
//
// Uninstall protocols installed by the driver in its entrypoint
//
Status = gBS->UninstallMultipleProtocolInterfaces (ImageHandle,
&gEfiDriverBindingProtocolGuid,
&gUsbDriverBinding,
NULL
);
return EFI_SUCCESS;
}