13.2.1 Device Drivers

Device drivers that implement RunDiagnostics() must verify that ChildHandle is NULL and that ControllerHandle represents a device that the device driver is currently managing. In addition, RunDiagnostics() must verify that the requested Language is in the set of languages that the UEFI Driver supports. The following example shows the steps required to check these parameters. If these checks pass, the diagnostic are executed and results are returned. In this specific example, the driver opens the PCI I/O Protocol in its Driver Binding Start() function. This is why gEfiPciIoProtocolGuid is used in the call to the EDK II Library UefiLib function EfiTestManagedDevice() that checks to see if the UEFI Drivers that is providing this RunDiagnostics() service is currently managing ControllerHandle. If the private context structure is required, typically the UEFI Boot Service OpenProtocol() is used to open one of the UEFI Driver produced protocols on ControllerHandle and then use a CR() based macro to retrieve a pointer to the private context structure.

Example 148-RunDiagnostics() for a Device Driver

#include <Uefi.h>
#include <Protocol/DriverDiagnostics2.h>
#include <Protocol/PciIo.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiLib.h>
EFI_STATUS
EFIAPI
AbcRunDiagnostics (
IN EFI_DRIVER_DIAGNOSTICS2_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle, OPTIONAL
IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType,
IN CHAR8 *Language,
OUT EFI_GUID **ErrorType,
OUT UINTN *BufferSize,
OUT CHAR16 **Buffer
)
{
EFI_STATUS Status;
CHAR8 *SupportedLanguages;
BOOLEAN Rfc4646Language;
BOOLEAN Found;
UINTN Index;
//
// ChildHandle must be NULL for a Device Driver
//
if (ChildHandle != NULL) {
return EFI_UNSUPPORTED;
}
//
// Make sure this driver is currently managing ControllerHandle
//
Status = EfiTestManagedDevice (
ControllerHandle,
gAbcDriverBinding.DriverBindingHandle,
&gEfiPciIoProtocolGuid
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check input parameters
//
if (Language == NULL || ErrorType == NULL ||
BufferSize == NULL || Buffer == NULL ) {
return EFI_INVALID_PARAMETER;
}
//
// Make sure Language is in the set of Supported Languages
//
SupportedLanguages = This->SupportedLanguages;
Rfc4646Language = (BOOLEAN)(This == &gAbcDriverDiagnostics2);
Found = FALSE;
while (*SupportedLanguages != 0) {
if (Rfc4646Language) {
for (Index = 0;
SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';
';
Index++);
if ((AsciiStrnCmp (SupportedLanguages, Language, Index) == 0) &&
(Language[Index] == 0)) {
Found = TRUE;
break;
}
SupportedLanguages += Index;
for (;
*SupportedLanguages != 0 && *SupportedLanguages == ';
';
SupportedLanguages++);
} else {
if (CompareMem (Language, SupportedLanguages, 3) == 0) {
Found = TRUE;
break;
}
SupportedLanguages += 3;
}
}
//
// If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
//
if (!Found) {
return EFI_UNSUPPORTED;
}
//
// Perform Diagnostics Algorithm on ControllerHandle for the
// type of diagnostics requested in DiagnosticsType
//
// Return results in ErrorType, Buffer, and BufferSize
//
// If Diagnostics Algorithm fails, then return EFI_DEVICE_ERROR
//
return EFI_SUCCESS;
}

To verify the operation of the controller, diagnostic algorithms typically use the services of the protocols the driver produces and the services of the protocols the driver consumes. For example, a PCI device driver that consumes the PCI I/O Protocol and produces the Block I/O Protocol can use the services of the PCI I/O Protocol to verify the operation of the PCI controller. Use the Block I/O Services to verify that the entire driver is working as expected.