每个USB设备都有个控制端点,用于在枚举过程中同USB Host进行通信,例如,读取设备描述符、分配地址等等...,都是通过端点0来完成的。对于端点来说,它都具有个发送或接收数据包的最大值,对于普通端点来说,它都在端点描述符中的wMaxPacketSize中被定义,但是端点0没有端点描述符,那么它就定义在USB设备描述符中的bMaxPacketSize0中。如果要和端点0进行通信,那么首先应该得到bMaxPakcetSize0这个值,但是没有通信如何得到这个值,难道进入了一个死循环?

我们都知道,对于低速设备来说,端点0的最大数据包长度为8字节,对于全速设备来说,可以8、16、32、或64字节,对于高速设备来说,只能是64字节,也就说端点0的最大数据包长度至少为8,而通过设备描述符发现,bMaxPacketSize0刚好定义在8字节处,也就是说可以先读取8字节的设备描述符,从而得到了bMaxPacketSize0这个值,那么以后的传输就可以按照最大数据包长度这个值来进行传输。Linux也正是按照这个策略来的。

但是有的USB设备并不这样,在你获取8字节的设备描述符的时候它会将18字节的设备描述符全部返回给你,这样就可能会导致错误,但是在Windows下不会。原来Windows下的做法是首先发送获取64字节的设备描述符请求,如果端点0的最大数据包长度是32或64,设备只需要将18字节的设备描述符全部返回即可,但是如果端点0的最大数据包长度是8或16,而设备描述符长度是18字节,不能一次性传完,那么没有关系,对设备做一次reset,清除本次控制传输,由于前面已经得到了端点0的最大数据包长度,那么后面同样以最大数据包长度来通信,这就是Windows下的做法。

所以后来在Linux代码中也加入了这种策略,谁让厂家在测试USB设备的时候是在Windows下进行的呢,所以说不得不妥协,其实Linux的那种策略才是USB协议提供的策略。在后来的代码中,即先采用Windows的策略获取描述符(默认2次),如果失败,再采用标准的方法(默认两次)。
Logo

更多推荐