设备匹配机制
id_table 指向一个 usbh_dev_id_t 类型数组,用于声明该驱动支持的设备。USB Core 在枚举过程中遍历此表,与插入设备的接口描述符进行匹配,以决定是否加载此驱动。
结构体定义
typedef struct {
u16 mMatchFlags; /* 匹配掩码 */
u16 idVendor; /* 厂商 ID (VID) */
u16 idProduct; /* 产品 ID (PID) */
u8 bDeviceClass; /* 设备级类代码 */
u8 bDeviceSubClass; /* 设备级子类代码 */
u8 bDeviceProtocol; /* 设备级协议代码 */
u8 bInterfaceClass; /* 接口级类代码 */
u8 bInterfaceSubClass; /* 接口级子类代码 */
u8 bInterfaceProtocol; /* 接口级协议代码 */
} usbh_dev_id_t;
匹配掩码
mMatchFlags 通过按位或组合的方式指定参与匹配的字段:
宏 |
值 |
说明 |
|---|---|---|
|
BIT0 |
匹配 |
|
BIT1 |
匹配 |
|
BIT2 |
匹配 |
|
BIT3 |
匹配 |
|
BIT4 |
匹配 |
|
BIT5 |
匹配 |
|
BIT6 |
匹配 |
|
BIT7 |
匹配 |
常用的组合宏:
宏 |
展开 |
|---|---|
|
|
|
|
|
|
匹配规则
Core 层遍历
id_table数组,依次检查设备/接口描述符中对应字段是否与条目一致。数组以
{}(全零条目)结束,表示表尾。仅
mMatchFlags中置位的字段参与比较,未置位的字段被忽略。所有参与比较的字段均一致时,判定为匹配成功。
复合设备的匹配特点
对于复合设备(例如 HID + UAC、CDC ACM + CDC ECM),驱动只需匹配到其中任意一个子功能的接口,即可确认设备在支持范围内。其余子功能在 attach 阶段通过独立的 usbh_dev_id_t 匹配找到各自接口。
备注
开发者可根据需求自定义 mMatchFlags,灵活配置匹配条件:
按 VID/PID 匹配(
USBH_DEV_ID_MATCH_DEVICE):仅支持特定厂商和型号的设备,匹配精度最高。按接口类/子类匹配(
USBH_DEV_ID_MATCH_ITF_CLASS或USBH_DEV_ID_MATCH_ITF_INFO):支持符合特定 USB 类规范的所有设备,兼容性最广。组合匹配**:将多个标志按位或组合,实现多维度的匹配条件(例如同时匹配 VID 和接口类)。
若
mMatchFlags中未包含对应标志位,即使设置了相应的字段值,该字段也不会参与匹配比较。
使用示例
以下按匹配级别分类展示 id_table 的典型用法。实际驱动代码可参考 {SDK}/component/usb/host/ 目录。
按 VID/PID 匹配(匹配特定设备)
要求设备的厂商 ID (VID) 和产品 ID (PID) 同时匹配时才加载驱动,适用于定制化硬件场景。
static const usbh_dev_id_t my_device_devs[] = {
{
.mMatchFlags = USBH_DEV_ID_MATCH_DEVICE, /* 展开为 VID | PID */
.idVendor = 0x0BDB,
.idProduct = 0x1234,
},
{ },
};
也可单独匹配 VID 或 PID:
static const usbh_dev_id_t my_vid_devs[] = {
{
.mMatchFlags = USBH_DEV_ID_MATCH_VID, /* 仅匹配厂商 ID */
.idVendor = 0x0BDB,
},
{ },
};
按设备描述符匹配(匹配设备级信息)
通过设备描述符中的 bDeviceClass / bDeviceSubClass / bDeviceProtocol 进行匹配,适用于设备级定义了 Class 的 USB 设备(例如 Hub)。
static const usbh_dev_id_t hub_devs[] = {
{
.mMatchFlags = USBH_DEV_ID_MATCH_DEV_CLASS,
.bDeviceClass = USB_CLASS_HUB,
},
{ },
};
也可使用 USBH_DEV_ID_MATCH_DEV_INFO 组合宏同时匹配类、子类和协议:
static const usbh_dev_id_t comm_devs[] = {
{
.mMatchFlags = USBH_DEV_ID_MATCH_DEV_INFO,
.bDeviceClass = 0x02, /* Communications Device 类 */
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
},
{ },
};
按接口描述符匹配(匹配接口级信息)
最常用的匹配方式,通过接口描述符中的 bInterfaceClass / bInterfaceSubClass / bInterfaceProtocol 匹配,适用于标准 USB 类驱动(MSC、CDC ACM、UAC、HID 等)。
仅匹配接口类
最简形式,仅按接口类识别设备,例如 MSC 驱动:
static const usbh_dev_id_t msc_devs[] = {
{
.mMatchFlags = USBH_DEV_ID_MATCH_ITF_CLASS,
.bInterfaceClass = MSC_CLASS_CODE,
},
{ },
};
匹配接口类 + 子类
进一步缩小匹配范围,适用于需要区分同一大类下不同子类的驱动,例如 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,
},
{ },
};
备注
上述 UAC 示例故意不匹配 bInterfaceProtocol,使 UAC 2.0 设备(protocol = 0x20)也能进入 attach 回调。驱动在 attach 中会给出明确的 "UAC 2.0 not supported" 提示,而非泛泛的 probe fail 信息,便于问题定位。
匹配接口类 + 子类 + 协议
精度最高的接口级匹配方式:
static const usbh_dev_id_t vendor_devs[] = {
{
.mMatchFlags = USBH_DEV_ID_MATCH_ITF_INFO, /* 展开为 ITF_CLASS | ITF_SUBCLASS | ITF_PROTOCOL */
.bInterfaceClass = VENDOR_CLASS_CODE,
.bInterfaceSubClass = VENDOR_SUBCLASS_CODE,
.bInterfaceProtocol = VENDOR_PROTOCOL,
},
{ },
};
组合匹配:接口类 + VID
多维匹配策略:先按接口类筛选,再锁定特定厂商范围:
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,
},
{ },
};
完整驱动注册
id_table 定义后需与 usbh_class_driver_t 驱动结构体关联,USB Core 在枚举时通过该结构体加载驱动:
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 类驱动 */
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,
};
驱动编写步骤
定义
id_table数组,以{ }(全零条目)标识数组结束。在
mMatchFlags中声明参与匹配的字段。填写对应的匹配值(接口类、VID/PID 等)。
将
id_table赋值给usbh_class_driver_t的.id_table成员。USB Core 在枚举阶段自动遍历
id_table,匹配成功则自动加载该驱动。