)
示例工程【免费下载链接】Windows-driver-samplesThis repo contains driver samples prepared for use with Microsoft Visual Studio and the Windows Driver Kit (WDK). It contains both Universal Windows Driver and desktop-only driver samples.项目地址https://gitcode.com/gh_mirrors/wi/Windows-driver-samples点击查看免费下载导读本文以微软官方驱动示例仓库中的 hid/hidusbfx2 为核心深入讲解如何基于 Windows Driver FrameworksWDF编写 HID 迷你驱动将一台不具备 HID 描述符的非 HID 标准 USB 设备OSR USB-FX2 学习板完整映射为操作系统可识别的 HID 设备。你将掌握 HID 类驱动hidclass.sys与 KMDF 驱动的调度表所有权冲突的经典解决方案、双驱动栈拆分架构、硬编码报告描述符的编写技巧以及选择性挂起Selective Suspend、开关去抖动、Feature 报告控制七段数码管与条形 LED 等完整实战能力。背景为什么需要自定义 HID 迷你驱动一个标准的 HID USB 设备会通过接口描述符Interface Descriptor提供 HID 描述符将自身标识为 HID 兼容设备。系统据此加载内置的 HID 迷你驱动hidusb.sys与 HID 类驱动hidclass.sys类驱动解析 HID 描述符并枚举出子 HID 设备栈。由于系统对 HID 设备支持非常完善绝大多数场景下你不需要编写 HID 迷你驱动。但存在两类必须自行编写 HID 迷你驱动的情形见 hid/hidusbfx2/README.md难以修改 HID 兼容设备的固件希望在现有固件能力之上通过软件层改变暴露给系统的 HID 行为把非 HID 兼容设备伪装成 HID 设备设备本身没有 HID 描述符又不打算更新固件则可以在驱动层补齐 HID 视图。HIDUSBFX2 示例正是第二种情形的完整范本目标设备是OSR USB-FX2 Learning Kit以 Cypress EZ-USB FX2 开发板 CY3681 为基础的非 HID 设备示例在驱动层为其凭空构建出完整的 HID 描述符与 HID 输入/Feature 报告让系统把它当 HID 设备使用。设备硬件概览接口与端点该设备含一个接口、三个端点Interrupt IN、Bulk Out、Bulk INInterrupt IN以 8 位值表示拨码开关Switch Pack状态在启动、从挂起恢复、开关状态变化时发送Bulk 端点配置为环回loopback用途固件厂商命令支持查询/设置 LED 条状图bar graph显示、7 段数码管显示以及查询拨码开关状态。开关数据的两个细节固件行为约束源码注释与 README 明确指出两点直接影响驱动设计无硬件去抖动固件不对拨码开关做 de-bounce 处理一次开关变化可能发送多个字节因此驱动必须自行实现软件去抖动见下文开关去抖动一节位序与标签相反8 位值中bit 0x80对应开关组上标记为 1 的开关即高位对应最左侧标签。源码中的 HIDFX2_INPUT_REPORT 结构体注释Individual switches starting from the right of the set of switches也印证了这一约定。驱动栈架构解决 HID 架构与 KMDF 的调度表冲突冲突的本质HID 架构要求hidclass.sys 拥有 HID 迷你驱动的分发表dispatch table以便正确处理 PnP、电源与 I/O 请求而 KMDF 框架同样要求驱动交出分发表控制权以注入框架回调。两者直接冲突因此KMDF 不能原生支持 HID 迷你驱动README 说明。经典解法最小 WDM 函数驱动 完整 KMDF 过滤驱动示例采用的架构README 描述hidclass.sys (HID 类驱动, 拥有上层分发表) │ 内部 IOCTL ▼ hidkmdf.sys (最小 WDM 函数驱动, 向 hidclass 注册) │ IRP 透传 ▼ hidusbfx2.sys (完整 KMDF 驱动, 作为下过滤驱动, 真正处理请求) │ ▼ USB 协议栈 → OSR USB-FX2 设备组件目录二进制职责函数驱动hid/hidusbfx2/hidkmdfhidkmdf.sys最小 WDM 驱动向 HID 类注册可原样复用过滤驱动hid/hidusbfx2/syshidusbfx2.sys完整 KMDF 驱动处理全部 HID 请求需按设备定制复用函数驱动时的注意事项hidkmdf.sys 是一个通用透传层无需修改即可复用但务必重命名二进制文件以避免名称冲突README 明确提醒见 L51。函数驱动的实现要点hidkmdf.chid/hidusbfx2/hidkmdf/hidkmdf.c 展示了 HID 迷你驱动的注册模型在DriverEntry中调用HidRegisterMinidriver注册HID_MINIDRIVER_REGISTRATION结构其中Revision必须为HID_REVISION并将DevicesArePolled FALSEUSB HID 设备无需 HID 类驱动轮询注释解释了 ping-pong IRP 机制见 L125-L132所有 IRP 默认走HidKmdfPassThroughIoCopyCurrentIrpStackLocationToNextIoCallDriver透传到下层电源 IRP 单独走HidKmdfPowerPassThroughPoStartNextPowerIrpPoCallDriver透传保证电源管理语义正确HidKmdfAddDevice不创建设备对象——注释明确说明hidclass 会替我们创建 FDO 并挂接到 PDO。将非 HID USB 设备映射为 HID核心原理当 HID 类驱动查询迷你驱动时迷你驱动返回硬编码的报告描述符report descriptorHID 类驱动依据该描述符创建子设备。HIDUSBFX2 的报告描述符声明了3 个顶层应用集合top-level application collections集合报告 ID用途Consumer control消费控制1应用启动/动作热键浏览器、计算器、邮件等System control系统控制2电源睡眠SleepVendor-defined厂商自定义37 段数码管与条形 LED 的 Feature 控制HID 类驱动会为每个顶层集合各创建一个驱动栈操作系统自动打开消费控制与系统控制集合数据来自 USB 中断端点厂商集合暴露 Feature 按钮任何客户端应用都可以打开该集合发送 Feature 请求README L55-L63。从源码看硬编码描述符定义在 hid/hidusbfx2/sys/hidusbfx2.h 的G_DefaultReportDescriptor数组中由#define USE_HARDCODED_HID_REPORT_DESCRIPTOR控制对应的G_DefaultHidDescriptorL241-L249给出 HID 描述符头与报告描述符长度hid.c中的HidFx2GetReportDescriptor/HidFx2GetHidDescriptor分别在IOCTL_HID_GET_REPORT_DESCRIPTOR/IOCTL_HID_GET_DEVICE_DESCRIPTOR时将这些硬编码数据拷贝给 HID 类驱动。完整报告描述符逐段解析以下是示例中硬编码报告描述符的完整内容含逐项注释来自 hid/hidusbfx2/sys/hidusbfx2.h1. Consumer control 集合报告 ID 10x05,0x0C, // USAGE_PAGE (Consumer Page) 0x09,0x01, // USAGE (Consumer Control Usage 0x01) 0xA1,0x01, // COLLECTION (Application) 0x85,0x01, // REPORT_ID (1) 0x0A, 0x23, 0x02, // USAGE (Usage Browser) 0x0A, 0x24, 0x02, // USAGE (Usage AC Back) 0x0A, 0x25, 0x02, // USAGE (Usage AC Forward) 0x0A, 0x27, 0x02, // USAGE (Usage AC Refresh) 0x0A, 0x2A, 0x02, // USAGE (Usage AC BookMarks) 0x0A, 0x8A, 0x01, // USAGE (Usage AL Mail) 0x0A, 0x92, 0x01, // USAGE (Usage AL Calculator) 0x15, 0x00, // LOGICAL_MINIMUM(0) 0x25, 0x01, // LOGICAL_MAXIMUM(1) 0x75, 0x01, // REPORT_SIZE (1 bit) 0x95, 0x07, // REPORT_COUNT (7) 0x81, 0x02, // INPUT (Data, Variable, Abs) 0x75, 0x01, // REPORT_SIZE 0x95, 0x01, // REPORT_COUNT 0x81, 0x07, // INPUT (const, 填充位) 0xC0, // END_COLLECTION7 个拨码开关位按位映射到 7 个消费控制 Usage第 8 位为常量填充位凑满 8 位。2. System control 集合报告 ID 20x05, 0x01, // Usage Page (Generic Desktop) 0x09, 0x80, // Usage (System Control) 0xA1, 0x01, // Collection (Application) 0x85, 0x02, // Report ID (2) 0x95, 0x07, // Report Count (7) 0x81, 0x07, // Input (Constant) -- PADDING 0x09, 0x82, // Usage (System Sleep) 0x95, 0x01, // Report Count (1) 0x81, 0x06, // Input (Data, Variable, Relative, Preferred) 0xC0, // End Collection最高位开关0x80映射为 System Sleep系统睡眠键。3. Vendor-defined Feature 集合报告 ID 3含 7 段数码管与条形 LED 两个子报告0x06,0x00, 0xFF, // USAGE_PAGE (Vendor Defined Usage Page 0xFF00) 0x09,0x01, // USAGE (Vendor Usage 0x01) 0xA1,0x01, // COLLECTION (Application) 0x85,0x03, // Report ID (3) -- 7 段数码管 0x19,0x00, // USAGE MINIMUM 0x29,0xff, // USAGE MAXIMUM 0x15,0x00, // LOGICAL_MINIMUM(0) 0x26,0xff, 0x00, // LOGICAL_MAXIMUM(255) 0x75,0x08, // REPORT_SIZE (8 bit) 0x95,0x01, // REPORT_COUNT (1) 0xB1,0x00, // Feature (Data, Ary, Abs) 0x85,0x04, // Report ID (4) -- 条形 LED 0x19,0x00, // USAGE MINIMUM 0x29,0xff, // USAGE MAXIMUM 0x15,0x00, // LOGICAL_MINIMUM(0) 0x26,0xff, 0x00, // LOGICAL_MAXIMUM(255) 0x75,0x08, // REPORT_SIZE (8 bit) 0x95,0x01, // REPORT_COUNT (1) 0xB1,0x00, // Feature (Data, Ary, Abs) 0xC0 // END_COLLECTION注意源码中的报告 ID 与 README 表格中的 Usage ID 对应关系报告 ID 3SEVEN_SEGMENT_REPORT_ID承载 7 段数码管 Feature报告 ID 4BARGRAPH_REPORT_ID承载条形 LED Feature宏定义见 hid/hidusbfx2/sys/hidusbfx2.h#L63-L67。开关映射表Consumer / System Control示例将拨码开关组映射为现代键盘常见的快捷键README 表格Switch12345678MappingSleepCalculatorMailFavoritesRefreshForwardBackBrowser结合位序约定0x80 标签 1可以推断标签 1Sleep对应最高位走 System Control 集合标签 2~8 依次对应低位 7 位0x40~0x01走 Consumer Control 集合。源码 usb.c 中的映射逻辑用CONSUMER_CONTROL_BUTTONS_BIT_MASK0x7F与SYSTEM_CONTROL_BUTTONS_BIT_MASK0x80划分两个集合的报告 ID。七段数码管与条形 LED 的 Feature 映射数码管与条形 LED 被映射为HID Feature 控件用户态应用可通过HidD_SetFeature函数操作。Feature 控件映射到厂商自定义 Usage Page 0xFF00README L75。七段数码管映射表Feature 数据字节与显示数字的对应关系README 表格Usage ID0xD70x060xB30xA70x660xE50xF40x070xF70x67MappingDisplay 0Display 1Display 2Display 3Display 4Display 5Display 6Display 7Display 8Display 9从源码角度这些字节实际是 7 段数码管各段SEGMENT_BIT_1~SEGMENT_BIT_8hidusbfx2.h#L92-L99按字形组合的结果例如SEGMENT_DISPLAY_1显示 1为SEGMENT_BIT_2 | SEGMENT_BIT_30x06、SEGMENT_DISPLAY_2显示 2为0xB3与表格逐项吻合。条形 LED 映射表条形 LED 按位点亮各值可 OR 组合以同时点亮多个 LEDREADME 表格Usage ID0x010x020x040x080x100x200x400x800xFF0x00MappingLED 1 ONLED 2 ONLED 3 ONLED 4 ONLED 5 ONLED 6 ONLED 7 ONLED 8 ONAll LEDs ONAll LEDs OFF源码 hidusbfx2.h#L154-L163 定义了BARGRAPH_LED_1_ON~BARGRAPH_LED_ALL_ON/OFF同名宏与表格完全一致。Feature 请求的底层实现hid.cIOCTL_HID_SET_FEATURE/IOCTL_HID_GET_FEATURE由 hid.c 的 HidFx2SetFeature / HidFx2GetFeature 处理校验HID_XFER_PACKET输入/输出缓冲区长度通过WdfRequestWdmGetIrp(Request)-UserBuffer直接取得用户缓冲区注释说明Set/Get Feature 不是 METHOD_NEITHER IOCTLKMDF 无法用WdfRequestRetrieveOutputMemory取得该缓冲区必须逃逸到 WDM 层按transferPacket-reportId区分SEVEN_SEGMENT_REPORT_ID4与BARGRAPH_REPORT_ID5调用SendVendorCommand/GetVendorData构造厂商 USB 控制传输WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR请求码如HIDFX2_SET_7SEGMENT_DISPLAY0xDB、HIDFX2_SET_BARGRAPH_DISPLAY0xD8、HIDFX2_READ_7SEGMENT_DISPLAY0xD4、HIDFX2_READ_BARGRAPH_DISPLAY0xD7并通过WdfUsbTargetDeviceSendControlTransferSynchronously同步下发带 5 秒超时WDF_REL_TIMEOUT_IN_SEC(5)防止用户线程被挂死。完整厂商命令表定义在 hidusbfx2.h#L81-L87命令宏值方向HIDFX2_READ_SWITCH_STATE0xD6设备 → 主机HIDFX2_READ_7SEGMENT_DISPLAY0xD4设备 → 主机HIDFX2_READ_BARGRAPH_DISPLAY0xD7设备 → 主机HIDFX2_SET_BARGRAPH_DISPLAY0xD8主机 → 设备HIDFX2_IS_HIGH_SPEED0xD9查询HIDFX2_REENUMERATE0xDA重枚举HIDFX2_SET_7SEGMENT_DISPLAY0xDB主机 → 设备输入报告通路中断端点连续读 开关去抖动USB 初始化usb.c在HidFx2EvtDevicePrepareHardwareusb.c#L42-L201中WdfUsbTargetDeviceCreate创建 USB 设备对象WdfUsbTargetDeviceSelectConfigWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE选择单接口配置用WdfUsbInterfaceGetConfiguredPipe按INTERRUPT_ENDPOINT_INDEX(0) 取得中断管道WdfUsbTargetPipeSetNoMaximumPacketSizeCheck允许读取小于最大包长的数据HidFx2ConfigContReaderForInterruptEndPoint在中断管道上配置WDF USB 连续读取器continuous reader每次读取sizeof(UCHAR)1 字节——这正好对应开关状态的一个字节。中断数据处理连续读取完成回调HidFx2EvtUsbInterruptPipeReadCompleteusb.c#L262-L398是输入通路的枢纽丢弃开机/唤醒首包IsPowerUpSwitchState标志为真时启动或从挂起恢复后的首个中断数据被丢弃该数据不是用户真实操作异或求变化toggledSwitch (previousSwitchState ^ currentSwitchState) currentSwitchState——固件总是返回全部开关状态驱动通过与上一次状态异或仅取从 0 变 1的开关作为本次按键事件启动去抖动定时器一旦检测到开关拨到 On就启动 10 ms 定时器SWICTHPACK_DEBOUNCE_TIME_IN_MS见 hidusbfx2.h#L74。定时器回调HidFx2EvtTimerFunctionusb.c#L733-L773在去抖窗口结束后调用HidFx2CompleteReadReport完成挂起的 HID 读请求。读请求排队与完成IOCTL_HID_READ_REPORT到达时hid.c#L129-L146驱动通过WdfRequestForwardToIoQueue将请求转发到手动队列InterruptMsgQueue该队列在 driver.c#L225-L240 创建并设置为非电源管理队列因为挂起的读请求无需等待设备完全上电去抖定时器触发后HidFx2CompleteReadReportusb.c#L401-L523从队列取回请求按掩码判断本次变化属于消费控制低 7 位还是系统控制最高位填入对应报告 ID 的HIDFX2_INPUT_REPORT以WdfRequestCompleteWithInformation完成。选择性挂起Selective Suspend支持HID 类驱动本身支持选择性挂起迷你驱动通过正确处理 HID 类 IOCTL参与该特性。关键路径在HidFx2EvtInternalDeviceControl中处理IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUESThid.c#L152-L180HidFx2SendIdleNotificationhid.c#L869-L969将该 IOCTL 转换为IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION透传给 USB 栈挂起等待。hidclass 是电源策略所有者它决定何时发送/取消空闲通知USB 栈判定设备空闲后完成请求触发 wait-wake IRP 并下电设备被重新打开或外部唤醒事件到来时再上电。启用方法通过 INF 在设备硬件键hardware key添加注册表值SelectiveSuspendEnabled 1。HIDUSBFX2 的 INFhid/hidusbfx2/sys/hidusbfx2.inx在厂商集合安装节中给出示例[customCollection.Inst.AddReg.NT.HW] HKR,,SelectiveSuspendEnabled,0x00000001,0x1同时驱动过滤部分还通过 INF 设置了AllowIdleIrpInD3[hidusbfx2_Parameters.AddReg] HKR,,AllowIdleIrpInD3,0x00010001,0x1注意INF 依赖 Windows 11 及以上hidusbfx2.inx头部注释明确声明L8-L9该 INF 依赖 Windows 11build 22000开始可用的特性——使用内置的mshidkmdf.inf作为 shim并通过AddFilter指令把 hidusbfx2 注册为下过滤驱动Lower Filter。若面向旧系统需要改写 INF 采用传统 co-installer 方式。构建与安装构建使用 Visual Studio WDK 打开解决方案 hid/hidusbfx2/hidusbfx2.sln 即可构建出hidusbfx2.sys与hidkmdf.sys两个驱动。需要复制的文件按 README 安装清单将以下文件复制到硬盘某文件夹hidusbfx2.inf由 hidusbfx2.inx 转换生成hidusbfx2.sysHidkmdf.sysWDF 联合安装程序coinstaller位于%ProgramFiles(x86)%\Windows Kits\8.0\redist\wdf\platform目录提示若未随 WDK 安装重分发组件可运行wdfcoinstaller.msi静默安装到 WDK 目录安装无确认提示可通过检查 WDK 根目录下是否存在redist\wdf子目录来验证。安装步骤插入设备在命令窗口运行devmgmt.msc打开设备管理器在其他设备分类下选中OSR USB-FX2 device右键选择更新驱动程序软件选择浏览计算机以查找软件提供驱动文件所在位置出现 Windows 安全对话框时选择仍然安装此驱动程序软件安装完成后设备应出现在设备管理器的**人体学输入设备Human Interface Devices**分类下。适配自己的设备将示例用于自有设备时需修改 INF 中的硬件 IDVID/PID与设备描述文本以匹配你的测试板README L97。示例 INF 中硬编码的硬件 ID 为USB\VID_0547PID_1002Cypress FX2 系列应替换为目标设备的 VID/PID。功能测试开关与显示测试开关映射无需任何用户态程序直接操作系统将 8 号开关拨到 On向下拨→打开 Web 浏览器将 2 号开关拨到 On →启动计算器应用。这验证了报告描述符中 Consumer 集合的 Browser0x0A 0x23 0x02与 Calculator0x0A 0x92 0x01映射已正确注册到系统。使用 HidClient 测试数码管与条形 LEDWindows 驱动工具包WDK自带的hidclient.exe图形应用可用来操纵显示。该应用的源码就位于本仓库的 hid/hclient 目录是演示用户态 HID 客户端应用的配套示例见 hid/hclient/README.md。操作流程README 测试步骤启动hidclient.exe在HID Device to examine下拉菜单中选择包含UsagePage 0ff00, Usage 01子字符串的设备——这正是厂商自定义集合的 Usage Page点击Modify Features打开 Feature Data 对话框在输入框输入7并点击Send to Device7 段数码管应显示数字 7输入 1~8数码管依次显示对应数字输入 9~17含边界条形 LED 依次点亮对应 条形 LED 映射表 中的各位。从实现上看hidclient 是通过HidD_SetFeature向报告 ID 3/4 的 Feature 集合发送单字节数据驱动侧HidFx2SetFeature再将其转换为厂商控制传输命令完成用户态 → HID 类驱动 → 过滤驱动 → USB 设备的完整链路。源码文件清单\hidusbfx2\hidkmdf函数驱动文件说明hid/hidusbfx2/hidkmdf/hidkmdf.c驱动入口与 IRP 透传分发hid/hidusbfx2/hidkmdf/hidkmdf.rc驱动资源文件hid/hidusbfx2/hidkmdf/hidkmdf.vcxprojVisual Studio 项目文件\hidusbfx2\sysKMDF 过滤驱动文件说明hid/hidusbfx2/sys/driver.cKMDF 驱动入口、DeviceAdd、队列与定时器创建hid/hidusbfx2/sys/hid.c处理全部 HID 内部 IOCTL描述符/属性/读报告/Feature/空闲通知hid/hidusbfx2/sys/usb.cUSB 配置、中断连续读、去抖、开关状态处理hid/hidusbfx2/sys/hidusbfx2.h类型定义、宏、报告描述符与函数声明hid/hidusbfx2/sys/hidusbfx2.inx驱动 INF 源文件构建时转换为 .infhid/hidusbfx2/sys/hidusbfx2.rc驱动资源文件hid/hidusbfx2/sys/trace.hWPP 跟踪相关定义复用与扩展建议函数驱动直接复用hidkmdf.sys是通用透传层换用任何设备都无需修改但必须重命名二进制报告描述符是定制核心设备暴露的按键、开关、传感器等能力全部通过改写G_DefaultReportDescriptor来定义——集合划分、Usage 选择、报告 ID、输入/Feature/输出属性都在这里决定改造输入通路若设备输入不是中断端点 单字节状态需要同步调整usb.c中的连续读配置与HidFx2CompleteReadReport的打包逻辑示例还预置了USE_ALTERNATE_HID_REPORT_DESCRIPTOR编译开关可切换到纯厂商集合上报开关状态的替代模式适合不希望系统自动处理按键的场景Feature 命令映射hid.c中SendVendorCommand/GetVendorData的厂商命令字0xD4~0xDB与目标设备固件协议一一对应需要按新设备固件改写注意版本约束当前 INF 面向 Windows 11 及更新版本面向旧系统部署时需改用传统 WDF co-installer INF 写法。通过上述架构与源码路径你可以完整复现非 HID 设备 → HID 设备的映射流程并以此为模板快速适配自己的硬件。赞分享示例工程【免费下载链接】Windows-driver-samplesThis repo contains driver samples prepared for use with Microsoft Visual Studio and the Windows Driver Kit (WDK). It contains both Universal Windows Driver and desktop-only driver samples.项目地址https://gitcode.com/gh_mirrors/wi/Windows-driver-samples点击查看免费下载相关推荐探索 node-hidNode.js 中的 USB HID 设备访问利器探索 node hid Node.js 中的 USB HID 设备访问利器 在现代软件开发中与硬件设备的交互变得越来越重要。 node hid 是一个强大的上一篇Kornia ManyToManyAugmentationDispather 输入校验强化数量不匹配立即报错杜绝静默丢弃下一篇WindowsCleaner终极C盘清理神器让你的系统重获新生创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考