HID设备读取输入报告机制概述
2022-05-30
668
0
在Windows系统中,一般是通过ReadFile中来获取输入报告的。我们在Windows系统HID设备获取报告描述符ReadFile和HidD_GetInputReport区别一文中介绍过它的大概原理。这里我们更加深理细节的说明一下ReadFile读取输入报告的细节原理。
在应用层,使用ReadFile函数读取输入报告,在内核层则进行了HIDCLASS.SYS中,其对应的IRP为IRP_MJ_READ。
在ReactOS中对应的函数为HidClass_Read,而Windows 10中为HidpIrpMajorRead。
在ReactOS中,可以通过源代码直接看到,是通过创建一个IRP,下发给HIDUSB.SYS中,然后设置完成例程,该IRP完成之后,将数据复制给IRP_MJ_READ。
Status = HidClass_BuildIrp(DeviceObject,
Irp,
Context,
IOCTL_HID_READ_REPORT,
IoStack->Parameters.Read.Length,
&NewIrp,
&NewIrpContext);
...
IoSetCompletionRoutine(NewIrp, HidClass_ReadCompleteIrp, NewIrpContext, TRUE, TRUE, TRUE);
这个不是Windows系统真正的实现机制,这是按需进行输入报告的读取,即需要上层调用ReadFile。
而在Windows中并不是这样实现的。
- HID设备PDO在启动设备(IRP_MN_START_DEVICE)开始,执行HidpStartCollectionPDO开启读输入报告。
- HidpStartCollectionPDO函数的具体流程是从父驱动FDO中找到其对应的子输入报告COLLECTION。
- HidpStartAllPingPongs函数使用2个PINGPANG的IPR来从HIDUSB.SYS中读取输入报告。
- 对于每个PINGPANG的IRP,读取输入报告的函数为HidpSubmitInterruptRead,其就是和ReactOS类似,下发IOCTL_HID_READ_REPORT来读取输入报告的内容。然后将收到的数据分发给上层打开该设备的所有HIDCLASS_FILE_EXTENSION(IRP_MJ_CREATE).这样当一个HID被上层多个应用打开时,只要有数据,会将数据分发给所有的已打开的设备。如我们通过SimpleHIDWrite工具打开同一个HID设备,当HID的输入报告时,会同时收到输入报告。如下图:
- HID输入报告的分发是通过HidpDistributeInterruptReport函数实现的。
- 在分发输入报告时,会有2种情况。
- 第一种情况是有待读的IRP_MJ_READ,那么从队列中取出PEDNING的IRP,完成并返顺。
- 第二种情况是虽然打开了HID设备(CreateFile,IRP_MJ_CREATE),但是没有读ReadFile,则将数据缓存。缓存的最大数据个数默认为32,可以由HidD_SetNumInputBuffers(IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS)来设置。
由于存在数据缓存,故也可以对缓存的输入报告进行清除。清除已经缓存的输入报API函数为HidD_FlushQueue,这其实也解释了CSDN上关于HID函数HidD_FlushQueue的问题,原网址为:https://bbs.csdn.net/topics/330044399
HID人机交互QQ群:564808376
UAC音频QQ群:218581009
UVC相机QQ群:331552032
BOT&UASP大容量存储QQ群:258159197
STC-USB单片机QQ群:315457461
USB技术交流QQ群2:580684376
USB技术交流QQ群:952873936