Device Matching Mechanism
id_table points to an array of usbh_dev_id_t that declares which devices this driver supports. During enumeration, the USB Core iterates through this table and matches it against the interface descriptor of the inserted device to decide whether to load this driver.
Structure Definition
typedef struct {
u16 mMatchFlags; /* Match mask */
u16 idVendor; /* Vendor ID (VID) */
u16 idProduct; /* Product ID (PID) */
u8 bDeviceClass; /* Device class code */
u8 bDeviceSubClass; /* Device subclass code */
u8 bDeviceProtocol; /* Device protocol code */
u8 bInterfaceClass; /* Interface class code */
u8 bInterfaceSubClass; /* Interface subclass code */
u8 bInterfaceProtocol; /* Interface protocol code */
} usbh_dev_id_t;
Match Flags
mMatchFlags uses a bitwise OR combination to specify which fields participate in matching:
Macro |
Value |
Description |
|---|---|---|
|
BIT0 |
Match |
|
BIT1 |
Match |
|
BIT2 |
Match |
|
BIT3 |
Match |
|
BIT4 |
Match |
|
BIT5 |
Match |
|
BIT6 |
Match |
|
BIT7 |
Match |
Commonly Used Composite Macros:
Macro |
Expansion |
|---|---|
|
|
|
|
|
|
Matching Rules
The Core iterates through the
id_tablearray and checks each entry against the corresponding fields of the device/interface descriptor.The array is terminated by
{ }(all-zero entry).Only fields with their corresponding bits set in
mMatchFlagsparticipate in comparison; unset fields are ignored.An entry is considered a match only when all participating fields are consistent.
Matching Characteristics
For a composite device (e.g., HID + UAC, CDC ACM + CDC ECM), the driver only needs to match one sub-function’s interface to confirm the device is within its support scope. Other sub-functions find their own interfaces through independent usbh_dev_id_t matching in the attach phase.
Note
Developers can customize mMatchFlags to flexibly configure matching conditions:
Match by VID/PID (
USBH_DEV_ID_MATCH_DEVICE): Supports only a specific vendor and product model - highest matching precision.Match by interface class/subclass (
USBH_DEV_ID_MATCH_ITF_CLASSorUSBH_DEV_ID_MATCH_ITF_INFO): Supports all devices conforming to a specific USB class - broadest compatibility.Combined matching: OR multiple flags to achieve multi-dimensional matching (e.g., match both VID and interface class).
If the corresponding flag is not set in
mMatchFlags, the field value is ignored during comparison even if it has been assigned.
Usage Examples
The following examples are organized by matching scope. Refer to {SDK}/component/usb/host/ for actual driver code.
Match by VID/PID (Specific Device)
Loads the driver only when both Vendor ID (VID) and Product ID (PID) match. Suitable for custom hardware scenarios.
static const usbh_dev_id_t my_device_devs[] = {
{
.mMatchFlags = USBH_DEV_ID_MATCH_DEVICE, /* Expands to VID | PID */
.idVendor = 0x0BDB,
.idProduct = 0x1234,
},
{ },
};
VID or PID can also be matched individually:
static const usbh_dev_id_t my_vid_devs[] = {
{
.mMatchFlags = USBH_DEV_ID_MATCH_VID, /* Match vendor only */
.idVendor = 0x0BDB,
},
{ },
};
Match by Device Descriptor
Matches using bDeviceClass / bDeviceSubClass / bDeviceProtocol from the device descriptor. Suitable for devices that define class at the device level (e.g., Hub).
static const usbh_dev_id_t hub_devs[] = {
{
.mMatchFlags = USBH_DEV_ID_MATCH_DEV_CLASS,
.bDeviceClass = USB_CLASS_HUB,
},
{ },
};
The USBH_DEV_ID_MATCH_DEV_INFO composite macro can match class, subclass, and protocol simultaneously:
static const usbh_dev_id_t comm_devs[] = {
{
.mMatchFlags = USBH_DEV_ID_MATCH_DEV_INFO,
.bDeviceClass = 0x02, /* Communications Device class */
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
},
{ },
};
Match by Interface Descriptor
The most common matching method, using bInterfaceClass / bInterfaceSubClass / bInterfaceProtocol from the interface descriptor. Suitable for standard USB class drivers (MSC, CDC ACM, UAC, HID, etc.).
Match by Interface Class Only
The simplest form - identifies devices by interface class alone, for example the MSC driver:
static const usbh_dev_id_t msc_devs[] = {
{
.mMatchFlags = USBH_DEV_ID_MATCH_ITF_CLASS,
.bInterfaceClass = MSC_CLASS_CODE,
},
{ },
};
Match by Interface Class + Subclass
Narrows the matching scope, suitable for drivers that differentiate subclasses within the same class, such as UAC:
static const usbh_dev_id_t uac_devs[] = {
{
.mMatchFlags = USBH_DEV_ID_MATCH_ITF_CLASS | USBH_DEV_ID_MATCH_ITF_SUBCLASS,
.bInterfaceClass = USB_UAC1_CLASS_CODE,
.bInterfaceSubClass = USB_UAC1_SUBCLASS_AUDIOSTREAMING,
},
{ },
};
Note
The UAC example intentionally omits bInterfaceProtocol so that UAC 2.0 devices (protocol = 0x20) still enter the attach callback, where the driver issues a clear “UAC 2.0 not supported” message instead of a generic probe failure - making debugging easier.
Match by Interface Class + Subclass + Protocol
The highest precision interface-level matching:
static const usbh_dev_id_t vendor_devs[] = {
{
.mMatchFlags = USBH_DEV_ID_MATCH_ITF_INFO, /* Expands to ITF_CLASS | ITF_SUBCLASS | ITF_PROTOCOL */
.bInterfaceClass = VENDOR_CLASS_CODE,
.bInterfaceSubClass = VENDOR_SUBCLASS_CODE,
.bInterfaceProtocol = VENDOR_PROTOCOL,
},
{ },
};
Combined Match: Interface Class + VID
Multi-dimensional matching: first filter by interface class, then narrow to a specific vendor:
static const usbh_dev_id_t uvc_devs[] = {
{
.mMatchFlags = USBH_DEV_ID_MATCH_ITF_CLASS | USBH_DEV_ID_MATCH_VID,
.idVendor = 0x0BDB,
.bInterfaceClass = USBH_UVC_CLASS_CODE,
},
{ },
};
Complete Driver Registration
The id_table must be associated with a usbh_class_driver_t struct for the USB Core to load the driver during enumeration:
static const usbh_dev_id_t cdc_acm_devs[] = {
{
.mMatchFlags = USBH_DEV_ID_MATCH_ITF_CLASS,
.bInterfaceClass = USB_CDC_CLASS_CODE,
},
{ },
};
/* USB Host CDC ACM class driver */
static usbh_class_driver_t usbh_cdc_acm_driver = {
.id_table = cdc_acm_devs,
.attach = usbh_cdc_acm_attach,
.detach = usbh_cdc_acm_detach,
.setup = usbh_cdc_acm_setup,
.process = usbh_cdc_acm_process,
};