设备描述符配置包 和 返回设备描述符
USB协议深入分析 设备描述符配置包
设备描述符配置包
在USB通讯里,从主控器发出来的第一个配置包就是设备描述符配置包,目的只有一个,就是获取插入的USB属性,以便加载合适的驱动程序。现在就来详细地分析一下设备描述符包的定义。
在USB2.0的协议里找到9.3 USB Device Requests里就找到这个结构的定义,这里我使用C的定义结构如下:
typedef
struct _USB_SETUP_PACKET
{
} USB_SETUP_PACKET;
bmRequestType是包含有下面几方面的内容:
D7 D6 D5 D4 D3 D2 D1 D0
在这一个字节里,又按位分为:
D7位是表示后面传送数据的方向位。
当D7等于0时,表示后面的数据是从主控器发送到USB设备。在PC里,就是从PC机发送到USB的设备。
当D7等于1时,表示后面的数据是从USB设备发送到主控器。在PC里,就是从USB设备发送到USB设备。在上次里,我收到并显示出来的数据是80,就表示从USB设备里发送数据给PC。在这里再次给出上一次的包数据:
80 06 00 01 00 00 40 00
这里的80,就是D7位为1。
D6-D5位是请求主分类型
0 是表示标准的请求。
1 是表示类别的请求。
2 是表示厂商的请求。
3 是保留。
D4-D0位是表求接收这个包的接口。
0 是表示USB设备接收。
1 是表示接口接收。
2 是表示端点接收。
3 是表示其它接收,不知道的。
4-31是保留。
bRequest是本描述符的请求类型,也就是后面发送的数据是什么样的东西。由于USB里有很多配置信息,比如获取设备描述符,又有设置USB地址等等,就是通过这个字节来区分的。
从USB协议里查找表9-4,就可看到如下的编码:
GET_STATUS 0
CLEAR_FEATURE 1
Reserved for future use 2
SET_FEATURE 3
Reserved for future use 4
SET_ADDRESS 5
GET_DESCRIPTOR 6
SET_DESCRIPTOR 7
GET_CONFIGURATION 8
SET_CONFIGURATION 9
GET_INTERFACE 10
SET_INTERFACE 11
SYNCH_FRAME 12
在上面的数据包里,看到它的内容是06,那么它就是
GET_DESCRIPTOR类型。也就是主控器想读取USB设备的描述符,到这里就已经分析出来的意思,就是主控器想读取USB描述符,但还不知道是什么描述符的内容。
wValue是根据不同的请求而设置不同的值。一般就是传送参数给设备标明这是什么请求。在上面
GET_DESCRIPTOR获取设备描述符里,它的值是00 01。在
GET_DESCRIPTOR里这个字段的低字节表示描述符的索引,高字节表示描述符的类型。高字节的类型如下:
DEVICE 1
CONFIGURATION 2
STRING 3
INTERFACE 4
ENDPOINT 5
DEVICE_QUALIFIER 6
OTHER_SPEED_CONFIGURATION 7
INTERFACE_POWER
1
8
wValue值在这里的高字节是01,那么它就是设备描述符了。低字节是00,那么它就是表示从偏移地址0开始读取设备描述符。由于在配置描述符里有很多配置,所以低字节在那里就可以用来识别获取同样类型的描述符不同的配置。
wIndex是根据不同的请求而设置不同的值。一般用来说明端点号或者说明接口标识。在获取描述符里,设置为0,或者是语言ID。在这个发送的描述符里,它是设置为00 00。
wLength是根据请求来决定下一阶段发送数据的长度。前面请求第一个字节里,已经说明下一阶段数据传送的方向,这里说明了传送数据的长度。不管是发送数据,还是接收数据,都不要超过这个数据长度,否则主机会出问题,或者设备有问题。在这个获取设备描述里,它的长度是40 00,按小端格式去解释,就是64个字节。
到这里,就把主控器发下来的数据解释完成了,知道去做什么的事情和回应。下一次就去分析怎么样返回设备描述符。
回应设备描述符
上一次已经介绍怎么样收到主控器的获取设备描述符的数据,这里就解释怎么样发送回应数据给主控器。
先从USB协议里找到标准设备的定义,我把它用C语言定义如下:
typedef
struct _USB_DEVICE_DESCRIPTOR {
} USB_DEVICE_DESCRIPTOR;
返回给主控器的数据结构就是上面的内容,只要把上面的结构填写合适的内容,就可以发送回去给主控器。在我的USB设备里,我把它填写如下的数据:
12 01 10 01 00 00 00 40 00 80 00 80 00 01 04 2C 4A 01
看到这串数据是不明白是什么东西的,现在就来仔细地分析它的具体定义。下面就按着一个字段一个字段地分析它。
bLength是本结构的数据长度,这样可以方便以后兼容不同的版本协议。因为不同的结构是不同的长度,这样就可以区分不同的协议了。比如有一天想添加一个字段,那么它的长度就会改变,这时就可以根据不同的长度进行解释不同的协议了。这次返回的结构长度是0x12,也就是18个字节,它的长度是从
bLength长度开始,也就是说是完全整个结构的长度。
bDescriptorType是描述符的类型。它的定义跟主控器发下来描述符的类型是一样的,如下:
DEVICE 1
CONFIGURATION 2
STRING 3
INTERFACE 4
ENDPOINT 5
DEVICE_QUALIFIER 6
OTHER_SPEED_CONFIGURATION 7
INTERFACE_POWER
1
8
由于返回的是设备描述符,所以就选择了1,也就是包里显示的第二个字节01。用这个类型来区分不同的描述符。
USB协议深入分析 返回设备描述符
bcdUSB是USB发布的协议版本。也就是本设备能适用于那种协议,目前USB主要有两个版本,一个是1.10,一个是2.10版本。在本设备里,采用了1.10的协议版本。由于这个字段是采用BCD编码,所以1.10的表示为0x0110的格式,按小端格式输出来,就变成10 01的显示了。
bDeviceClass是设备分类。当它的值是0时,表示所有接口在配置描述符里,并且所有接口是独立的。当它的值是1到FEH时,表示不同的接口关联的。当它的值是FFH时,它是厂商自己定义的。在这个设备里,是定义为0。
bDeviceSubClass是设备子分类码。当前面的
bDeviceClass值是0时,这里一定要设置为0。其它就跟据USB-IF组织定义的编码。
bDeviceProtocol是设备使用的协议。如果使用USB-IF组织定义的协议,就需要设置这里的值。如果不使用,就直接设置为0。如果厂商自己定义的可以设置为FFH。
以上三个值,在本设备里全部设置为0。
bMaxPacketSize0是端点0收发最大的包大小。仅允许设置8,16,32,64中的任何一个大小。在本设备里是设置为64个字节大小。所以看到这个字段是40 的大小。
12 01 10 01 00 00 00 40 00 80 00 80 00 01 04 2C 4A 01
idVendor是厂商标识。由USB-IF分配的编码。在这里使用0x8000。
idProduct是厂商定义的产品标识。由厂家和产品标识,就可以让操作系统加载不同的驱动程序。如下:
12 01 10 01 00 00 00 40 00 80 00 80 00 01 04 2C 4A 01
bcdDevice是用BCD表示的设备发布的版本号。这里是1.00。
12 01 10 01 00 00 00 40 00 80 00 80 00 01 04 2C 4A 01
iManufacturer是厂商字符串的偏移值。这值主要说明了它在字符串描述符里的偏移位置。如果它设置为0,表示没有厂商字符串。在这里是0x04,就是从字符串描述符开始位置算起第4个字节位置读取字符串。
iProduct是产品字符串的偏移值。这值主要说明了它在字符串描述符里的偏移位置。如果它设置为0,表示没有产品字符串。在这里是0x2C,就是从字符串描述符开始位置算起第2C个字节位置读取字符串。
iSerialNumber是序列号字符串的偏移值。这值主要说明了它在字符串描述符里的偏移位置。如果它设置为0,表示没有序列号字符串。在这里是0x4A,就是从字符串描述符开始位置算起第4A个字节位置读取字符串。
所有字符串,都是采有UNICODE编码。
bNumConfigurations是配置描述符的个数。在这里只使用了一个配置,所以设置为1。