设备匹配机制

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 通过按位或组合的方式指定参与匹配的字段:

说明

USBH_DEV_ID_MATCH_VID

BIT0

匹配 idVendor

USBH_DEV_ID_MATCH_PID

BIT1

匹配 idProduct

USBH_DEV_ID_MATCH_DEV_CLASS

BIT2

匹配 bDeviceClass

USBH_DEV_ID_MATCH_DEV_SUBCLASS

BIT3

匹配 bDeviceSubClass

USBH_DEV_ID_MATCH_DEV_PROTOCOL

BIT4

匹配 bDeviceProtocol

USBH_DEV_ID_MATCH_ITF_CLASS

BIT5

匹配 bInterfaceClass

USBH_DEV_ID_MATCH_ITF_SUBCLASS

BIT6

匹配 bInterfaceSubClass

USBH_DEV_ID_MATCH_ITF_PROTOCOL

BIT7

匹配 bInterfaceProtocol

常用的组合宏:

展开

USBH_DEV_ID_MATCH_DEVICE

VID | PID (按厂商和产品匹配)

USBH_DEV_ID_MATCH_DEV_INFO

DEV_CLASS | DEV_SUBCLASS | DEV_PROTOCOL (按设备类信息匹配)

USBH_DEV_ID_MATCH_ITF_INFO

ITF_CLASS | ITF_SUBCLASS | ITF_PROTOCOL (按接口类信息匹配)

匹配规则

  • 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_CLASSUSBH_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,
};

驱动编写步骤

  1. 定义 id_table 数组,以 { } (全零条目)标识数组结束。

  2. mMatchFlags 中声明参与匹配的字段。

  3. 填写对应的匹配值(接口类、VID/PID 等)。

  4. id_table 赋值给 usbh_class_driver_t.id_table 成员。

  5. USB Core 在枚举阶段自动遍历 id_table,匹配成功则自动加载该驱动。