Windows动态库hid.dll
+ -

HID设备空闲态的状态检测

2022-06-07 276 0

HIDCLASS.SYSS中使用一个一个周期为1秒间隔的定时器来周期性地检查设备空闲检测。

#define HID_IDLE_SCAN_INTERVAL 1
scanTime = RtlConvertLongToLargeInteger(-10*1000*1000 * HID_IDLE_SCAN_INTERVAL);

KeSetTimerEx(&idleTimer,
                   scanTime,
                   HID_IDLE_SCAN_INTERVAL*1000,    // call wants milliseconds
                   &idleTimerDpc);

当然,这里的1秒并不是说明设备1秒,而是检查的周期间隔为1秒,而空闲的时长可由驱动指定,这里指定为5,所以也就是说5秒。

当检测到了5次即5䚱时,由HIDCLASS.SYS发送一个IRP到HUB,再由HUB驱动程序的端口进行设置。

而执行的IRP为IRP_MJ_INTERNAL_DEVICE_CONTROL,控制码为IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST,不过在下发该IRP时,会传递一个回调函数及上下文信息组成的结构体指针,使用的的是InputBufferLength和Type3InputBuffer。

 stack = IoGetNextIrpStackLocation(irp);
 stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
 stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST;
 stack->Parameters.DeviceIoControl.InputBufferLength = sizeof(fdoExt->idleCallbackInfo);
 stack->Parameters.DeviceIoControl.Type3InputBuffer = (PVOID) &(fdoExt->idleCallbackInfo); 

 //
  // Hook a completion routine for when the device completes.
  //
  IoSetCompletionRoutine(irp,
                         HidpIdleNotificationRequestComplete,
                         DeviceObject->DeviceExtension,
                         TRUE,
                         TRUE,
                         TRUE);

当然,HIDCLASS.SYS发送该IRP,也需要知道什么时候该IRP完成了,故需要设置一个完成例程。
HIDCLASS.SYS下发的该IRP会首先发给hidusb.sys,hidusb.sys进行转发,不过由于hidusb.sys和hidclass.sys复杂的关系,故不会像别的驱动栈那样直接IoSkipCurrentStactionIrp,再IoCallDriver等。
而hidusb.sys会将IOCTL码变为IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION。

 next->MajorFunction = current->MajorFunction;
 next->Parameters.DeviceIoControl.InputBufferLength =  current->Parameters.DeviceIoControl.InputBufferLength;
 next->Parameters.DeviceIoControl.Type3InputBuffer = 
     current->Parameters.DeviceIoControl.Type3InputBuffer;
 next->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
 next->DeviceObject = GET_NEXT_DEVICE_OBJECT(DeviceObject);

 return IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);

hidusb.sys转发的IPR最终由HUB驱动的USBPORT_PdoDeviceControl函数处理,详细的可见ReactOS源代码:https://doxygen.reactos.org/d6/d69/usbhub_8c_source.html#l03722 可见实际的处理函数为USBPORT_IdleNotification。

USBH_PortIdleNotificationRequest的处理比较简单,就是将该IRP挂起,并保存起来,设置端口标识USBHUB_PDO_FLAG_IDLE_NOTIFICATION。

当然,关于该IRP的完成,会出现多种状态,如返回不支持空闲态检测,应取消空闲态求。

大概看了REACTOS的源代码,设备的IDLE请求与HUB的IDLE有关,至于细节,本人确实无精力研究。。。

扩展信息可详见微软文档:https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-power-manager-routines-for-idle-detection

HID人机交互QQ群:564808376    UAC音频QQ群:218581009    UVC相机QQ群:331552032    BOT&UASP大容量存储QQ群:258159197    STC-USB单片机QQ群:315457461    USB技术交流QQ群2:580684376    USB技术交流QQ群:952873936   

0 篇笔记 写笔记

HID 设置空闲SetIdle
SetIdle用于设置HID设备空闲速率。默认情况下,空闲速率为0。SetIdle是一个非必要请求。bmRequestType(1):0x21bRequest(1): SET_IDLE,值为0A.wValue(2):高字节用于指定空闲速率,以4ms为单位,可选的值为4ms~1020ms,低字节......
HID 获取空闲请求GetIdle
GetIdle用于获取HID设备空闲速率。空闲速率是指当HID设备没有数据报告时,主机限制中断输入端点的报告间隔时间。默认情况下,空闲速率为0。GetIdle是一个非必要请求。详见:USB请求bmRequestType(1):0xa1bRequest(1): GET_IDLE,值为02.wVa......
HID设备空闲态的状态检测
在HIDCLASS.SYSS中使用一个一个周期为1秒间隔的定时器来周期性地检查设备空闲检测。#define HID_IDLE_SCAN_INTERVAL 1scanTime = RtlConvertLongToLargeInteger(-10*1000*1000 * HID_IDLE_SCAN_......
关注公众号
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!