19.3.1 Driver Binding Protocol Supported()
USB device drivers must implement the EFI_DRIVER_BINDING_PROTOCOL
that
contains the Supported()
, Start()
, and Stop()
services. The Supported()
service checks the passed-in controller handle to determine whether this handle
represents a USB device that the driver knows how to manage.
The following is the most common method for doing the check:
- Check if this handle has
EFI_USB_IO_PROTOCOL
installed. If not, this handle is not a USB device on the current USB bus. - Get the USB interface descriptor back from the USB device. Check whether the values of this device's InterfaceClass, InterfaceSubClass, and InterfaceProtocol are identical to the corresponding values this driver can manage.
If the handle passes the above two checks, the USB device driver can manage the device
that the controller handle represents and the Supported()
service returns
EFI_SUCCESS
. Otherwise, the Supported()
service returns EFI_UNSUPPORTED
.
In addition, this checking process must not disturb the current state of the USB
device because the USB device may be managed by another USB device driver.
The example below shows an implementation of the Driver Binding Protocol
Supported()
service for a USB keyboard driver. It opens the USB I/O Protocol
with an attribute of EFI_OPEN_PROTOCOL_BY_DRIVER
. It then uses the
UsbGetInterfaceDescriptor()
service of the USB I/O Protocol and evaluates the
class, subclass, and protocol fields of the interface descriptor to see if the
description is for a USB keyboard.
Example 206-Supported() for a USB device driver
#include <Uefi.h>
#include <Protocol/DriverBinding.h>
#include <Protocol/UsbIo.h>
#include <Library/UefiBootServicesTableLib.h>
#define CLASS_HID 3
#define SUBCLASS_BOOT 1
#define PROTOCOL_KEYBOARD 1
EFI_STATUS
EFIAPI
AbcSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
EFI_STATUS Status;
EFI_USB_IO_PROTOCOL *UsbIo;
EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
//
// Open the USB I/O Protocol on ControllerHandle
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiUsbIoProtocolGuid,
(VOID **)&UsbIo,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get the USB Interface Descriptor
//
Status = UsbIo->UsbGetInterfaceDescriptor (
UsbIo,
&InterfaceDescriptor
);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Check to see if the interface descriptor is supported by this driver
//
if (InterfaceDescriptor.InterfaceClass != CLASS_HID || InterfaceDescriptor.InterfaceSubClass != SUBCLASS_BOOT ||
InterfaceDescriptor.InterfaceProtocol != PROTOCOL_KEYBOARD ) {
Status = EFI_UNSUPPORTED;
}
Done:
//
// Close the PCI I/O Protocol
//
gBS->CloseProtocol (
ControllerHandle,
&gEfiUsbIoProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
return Status;
}
Because the Supported()
service is invoked many times, the USB bus driver in
EDK II makes certain optimizations. The USB bus driver caches the interface
descriptors, eliminating the need to read them from the USB device every time a
USB device driver's Supported()
service is invoked.