HID设备ReportId冲突的验证探讨
需求永远是变态的,但能完成这个变态的需求,只能说我们也是极度的变态。
有这么一个需求,一个自定义的HID设备,假如其ReportId分别为1,3,5用于输入,2,4,6用于输出。并且其原有的功能是可以稳定的工作的。
不过现在我们有个需求,就是在不修改固件的情况下,对原有的ReportId=1时,进行扩展。就是需要区分ReportId=1时的两种情况,一种是我们自己的,一种是原有固件自身的功能。
其实想到的第一种方案就是进行报告描述符来复合,这样hidclass.sys通过hidparser.sys解析报告描述符之后,会生成两个HID设备,不过由于通过报告描述符复合,那么由于ReportId公用的冲突,系统会不知道当ReportId=1时,到底是发给那个应用集合。
我们通过报告描述符复合,其实就是写两个相同层级的 Collection (Application),其结构大概如下:
0x06, 0xFF, 0x00, // Usage Page (Vendor Defined 0xFFA0)
0x09, 0x01, // Usage (0x01)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID(1)
....
0xC0, // End Collection
0x06, 0xFF, 0x01, // Usage Page (Vendor Defined 0xFFA0)
0x09, 0x01, // Usage (0x01)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID(1)
....
0xC0, // End Collection
这里可以通过Usage Page和Usage在应用层来判断是那个设备。不过这里系统是区分了,设备端是无法区分的。所以主机会对此显示错误,我们按照上面的思路在系统中虚拟一个这样的设备,那么在设备管理器中如下:
可以看到,设备管理器中设备该设备以黄色感叹号显示,表示设备启动失败。
设备状态显示:
This device cannot start. (Code 10)
Report ID declaration found outside of top level collection.
翻译过来说是ReportId的顶层集合之找到,其实真正的原因是因为我们ReportId重复导致。
我们通过修改其中一个的ReportId不重复,可正常加载。
当然,也可以用我们的HidTool来打开设备进行输入输出报告通讯。
那么基于以上的这个问题验证,真实情况们该怎么验证呢?
这里可以向上考滤一层,就是通过接口描述答来复合设备。即将这2个Collection (Application)分别指给不同的接口描述符,这样实现在接口层的复合。这样各个接口描述符中指定的Application中均含有ReportId=1时,也相互不影响。
其实这里也从另一个方面来验证了USB的设备寻址思想:
- USB总线
- USB设备地址
- USB接口
- USB端点
- [HID ReportId]