Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1138120
  • 博文数量: 241
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 2279
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-27 19:53
个人简介

JustForFun

文章分类

全部博文(241)

文章存档

2023年(8)

2022年(2)

2021年(3)

2020年(30)

2019年(11)

2018年(27)

2017年(54)

2016年(83)

2015年(23)

我的朋友

分类: LINUX

2018-04-18 17:46:26

【整理】Windows,Linux,Mac系统中,USB HID枚举过程的异同

【背景】 
遇到一个问题,即一个设备,用的Silicon的C8051F347的MCU,其中的USB的驱动的HID部分,在Hid_Class_Request函数中, 
把GET_REPORT对应的代码,注释掉了,即没有实现对应的GET_REPORT的功能。 
由此,导致设备连接到某台Linux PC中,设备无法响应HID的GET_REPORT,因此无法正常工作。 
此问题,已经被别人debug后,找到此处代码的原因了。 
而我此处的疑问是,经过查找代码修改的历史记录,发现最原始的代码,是实现了GET_REPORT部分的功能的,但是却在后来某个版本注释掉了此部分代码。 
所以很是困惑,为何代码作者会注释掉此部分的代码,因为,看起来,USB的HID的spec: 
HID1_11 – USB Device Class Definition for Human Interface Devices(HID).pdf 
中, 
是有说明的: 
7.2.1 Get_Report Request 
The Get_Report request allows the host to receive a report via the Control pipe. 
没有说明是可选的,就说明此功能,是必须支持的。意味着,按照HID的spec来说,代码中,必须要实现此功能的。

【解决过程】 
后来去网上找了版本,最后终于找到有人解释的很清楚了: 
Difference on HID enumeration on Win, Linux and Mac 
 
简单来说,就是,不同的操作系统,USB HID枚举时候的做法,都不太相同。 
而对于此处的问题来说,就是: 
Windows中对于USB HID的枚举,不会发送GET_REPOR给设备,即用不到GET_REPOR,所以设备端的驱动,可以不实现此功能; 
而Linux中对于USB HID的枚举,会发送GET_REPOR去获取Input的内容,所以设备端的驱动,必须要实现此功能。 
其中,Linux的做法,是符合USB的HID的规范的。 
但是,现实就是现实,由于Windows的用户足够多,所以,很多驱动开发者,往往就默认地接受了Windows的很多做法, 
导致其功能的实现,是按照Windows的做法,而不是协议规范的做法。

【总结】 
借用上面那个帖子中所说的,以后写驱动的话,对于USB的特定的枚举过程或顺序,不能完全指望协议,即,也要了解现实世界的做法,即Linux,Windows,Mac中,USB HID的枚举过程,是不太一样的,作为驱动开发者,最好都要清楚,然后尽可能地都支持这些系统。

下面对 
Difference on HID enumeration on Win, Linux and Mac 
 
进行简单翻译如下,以对不同系统中,USB HID枚举过程的异同做出一些总结: 
【Windows,Linux,Mac系统中,USB HID枚举过程的异同】 
对于不同的OS之间,枚举顺序的不同,下面以SiLabs HID/Blinky(vendor specific HID设备)为例,一一列出来: 
注意,此处列出来的,只是设备连接到PC上之后,PC端的程序还没有运行期间的设备枚举的过程。
1. 总线重置(Bus Reset) 
WinXp和Linux都会reset两次。

2. Get_Descriptor( Device ) and Get_Descriptor( Config ) 
WinXP会发送两次Get_Descriptor

3. SET_IDLE 
WinXP是在SET_CONFIGURATION之后,发送SET_IDLE

4. interrupt IN/ GET_REPORT 
WinXP和Mac OS,使用中断输入端点(interrupt IN EP)发送IN传输(IN transfer),然后继续执行,而忽略主机端程序。 
而Linux发送GET_REPORT( input ),且在主机端程序开始运行之前,不会向发送中断端点( interrupt EP)发送IN传输

上述中,最主要的区别,不是枚举过程的顺序本身,而是枚举之后的interrupt IN/ GET_REPORT。

而虽然USB HID的规范中,已经说明了GET_REPORT(input) 是必须支持的一个功能,但是由于WinXP在枚举期间,不发送GET_REPORT(input), 
所以实际上,驱动实现者,常常都不去实现此GET_REPORT(input)的功能。

同时,要注意的是,由于Linux在主机端程序运行之前,是不会向中断端点(interrput EP)发送IN请求(IN request )的,所以,固件(firmware)端,如果期望的是Host端是周期性地会发送请求到中断端点(IN EP)的话,那么程序就会出错了。 
即,USB设备端的程序开发者,在写USB驱动程序的时候,要知道上面那些特殊情况,即Host端,即如果是PC端运行的是Linux系统的话,那么在Linux系统程序执行之前, 
USB设备端的IN EP,是收不到对应的IN请求的,这点,写驱动的时候,要自己注意,不能自己假定,设备端,会周期性地,从Host端收到IN请求,如果你是按照这样的逻辑实现的驱动,那么遇到Host端运行的是Linux系统的话,由于收不到对应IN请求,所以程序就不是按照你所期望的去运行了,就出错了。

注:原帖有各个OS中枚举过程的详细的列表对比,现粘贴如下,如果格式很乱,就自己去看格式清晰的:

WinXP sp2 | Linux Kernel 2.6.19 | MacOSX 10.4.9-10.4.10 
value index len | value index len | value index len 
RESET | RESET | RESET 
GET_DESCRIPTOR DEVICE 0100 0000 64 | GET_DESCRIPTOR DEVICE 0100 0000 64 | GET_DESCRIPTOR DEVICE 0100 0000 
8 
RESET | RESET | 
SET_ADDRESS 0002 0000 0 | SET_ADDRESS 0003 0000 0 | SET_ADDRESS 0003 0000 0 
GET_DESCRIPTOR DEVICE 0100 0000 18 | GET_DESCRIPTOR DEVICE 0100 0000 18 | GET_DESCRIPTOR DEVICE 0100 0000 18
 
| | GET_DESCRIPTOR STRING 0302 0409 2 
| | GET_DESCRIPTOR STRING 0302 0409 10 
| | GET_DESCRIPTOR STRING 0301 0409 2 
| | GET_DESCRIPTOR STRING 0301 0409 10 
GET_DESCRIPTOR CONFIG 0200 0000 9 | GET_DESCRIPTOR CONFIG 0200 0000 9 | GET_DESCRIPTOR CONFIG 0200 0000 4 
GET_DESCRIPTOR CONFIG 0200 0000 255 | GET_DESCRIPTOR CONFIG 0200 0000 34 | GET_DESCRIPTOR CONFIG 0200 0000 34
 
GET_DESCRIPTOR STRING 0300 0000 255 | GET_DESCRIPTOR STRING 0300 0000 255 | 
GET_DESCRIPTOR STRING 0302 0409 255 | GET_DESCRIPTOR STRING 0302 0409 255 | 
GET_DESCRIPTOR STRING 0300 0000 255 | GET_DESCRIPTOR STRING 0301 0409 255 | 
GET_DESCRIPTOR STRING 0302 0409 255 | | 
GET_DESCRIPTOR DEVICE 0100 0000 18 | | 
GET_DESCRIPTOR CONFIG 0200 0000 9 | | 
GET_DESCRIPTOR CONFIG 0200 0000 34 | | 
SET_CONFIGURATION 0001 0000 0 | SET_CONFIGURATION 0001 0000 0 | SET_CONFIGURATION 0001 0000 0 
SET_IDLE 0000 0000 0 | | 
GET_DESCRIPTOR HID REP 2200 0000 147 | GET_DESCRIPTOR HID REP 2200 0000 83 | GET_DESCRIPTOR HID REP 2200 0000 83 
| | GET_DESCRIPTOR STRING 0301 0409 2 
| | GET_DESCRIPTOR STRING 0301 0409 10 
| | GET_DESCRIPTOR STRING 0302 0409 2 
| | GET_DESCRIPTOR STRING 0302 0409 10 
IN EP=81 | GET_REPORT 0104 0000 2 | IN EP=81 
IN EP=81 | GET_REPORT 0105 0000 3 | IN EP=81 
SOF IN/NAK | SOF | SOF IN/NAK
阅读(2193) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~