Windows和Linux不同主机下USB设备枚举过程中的差别
第一次获取设备描述符的不同
USB设备刚上电时,是通过端点0使用控制方式来获取设备描述符。不同的设备模式获取端点0的大小不同的:
由于USB主机和USB设备第一次通讯时,所以并不知道端点0的最大包长度,所以不能正确检测控制传输中的数据段的结束。
如果USB主机指定USB端点0的最大包长度为64字节,而实际USB的端点0最大包长度为8字节,但由于USB设备描述符的的长度为18字节,USB主机在获取第一个GET_DESCRIPTOR设备描述符时要求设备返回18字节的数据。但对于USB设备由于其端点0的最大包长度为8字节,所以18个字长的设备描述符需要3次事务传输过铖,分别为8字节,8字节和2字节的事务传输。但由于USB主机发起的事务指定的数据长度为64字节或设备描述符18字节,所以当USB主机收到8字节时由于收到的数据长度小于其假定的最大包长度64字节时,USB主机认为数据阶段已经完成,而USB设备此时还在准备在发送第二个字节的事务,所以这会导致通讯双方的状态不同步而导致无法完成。
所以针对以上问题,不同的操作系统使用不同的解决方案。
Windows下的解决方案
对于Windows操作系统,主机要求返回64字节的设备描述符并默认设备端点0的最大包长度为64字节了,如果设备端点0的最大长度不小于标准描述符的长度(18字节),那么USB设备就可以一次将18个字节的设备描述符发送给主机,通信的双方保持同步;如果设备的端点0最大包长度小于设备描述符的18字节长度,那么此时USB设备面要使用多个事务向主机发送一个完整的设备描述符,前述的不同步问题会出现。对此,Windows7系统在第一次获取设备描述符后,直接进行复位(Reset),将设备状态重置为初始状态。 而由于设备端所支持的最小的最大包长度为8.此时主机一定能获取到设备描述符的前8个字节:而设备描述符的第8个字节)就是设备端点0所支持的最大包长度。主机可以在后续的控制传输中使用这个设备端的最大包长度来保证双方正常通信。所以“Reset”就是这个解决方案的关键点。
Linux Ubuntu下的解决方案
而在Linux Ubuntu的解决方案如下:
主机第一次获取设备描述符时只获取其前8字节。此时,不管USB设备 端点的最大包长度是多少,USB设备只能发送8字节的数据,同时通信双方 同步结束数据阶段。之后USB主机读取USB设备描述符的第8个字节,得 到设备端点0的最大包长度,并用于后续的控制传输。这个解决方案的关键 点就是第一次获取设备描述符时只获取其前8字节。
这两种解决方案都能解决实际的问题,但是解决问题的思路有所不同, Wndos7的解决方案是一种异常处理的方式,而LimmxUbunt的解决方案 则体现了一种精细控制、避免出错的思想。读者可以根据自己的实际情况选 择相应的解决方案。
获取配置描述符的不同
USB主机复位设备后,这时会使用18字节的长度获取设备描述符。然后紧跟着的一般是获取配置描述符。
在Windows下,在获取第一次配置描述符其实是经过了三次。
- 第一次使用255字节获取
- 第二次使用9字节获取
- 第三次使用实际的长度获取
而在Linux Ubuntu下只有后两次。