一.设备描述符配置包
typedef struct
{
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
}USB_SETUP_PACKET;
假设数据包为:80 06 00 01 00 00 40 00
-
bmRequestType
bit 7: data transfer direction 传输方向 0:HOST-to-device 下传 1:Device-to-host 上传 bit 6-5: Type 请求类型 0:Standard 标准请求 1:Class 类请求 2:Vendor 厂商请求 3:Reserved 保留 bit 4-0: Recipient 接收对象 0:Device 设备接收 1:Interface 接口接收 2:Endpoint 端点接收 3:Other 其他 4-31:Reserved 保留
-
bRequest
描述符的请求类型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_CONFIGUARTION 8 SET_CONFIGUARTION 9 GET_INTERFACE 10 SET_INTERFACE 11 SYNCH_FRAME 12
06
:表示GET_DESCRIPTOR
,可以得知主机想要获取USB
设备的描述符,但是还不清楚具体是什么类型的描述符。 -
wValue
在
GET_DESCRIPTOR
这个字节中,低字节表示描述符的索引,高字节表示描述符的类型,高字节的类型如下:DEVICE 1 CONFIGUARTION 2 STRING 3 INTERFACE 4 ENDPOINT 5 DEVICE_QUALIFIER 6 OTHER_SPEED_CONFIGURATION 7 INTERFACE_POWER1 8
wVlaue:00 01
:表示从偏移地址0
开始读取描述符,01
表示设备描述符。 -
wIndex
是根据不同的请求而设置不同的值,一般用来说明端点号或者说明接口标识,在获取描述符里,设置为0
,或者是语言ID
,在这个发送的描述符里,它是设置为00 00
。 -
wLength
是根据请求来决定下一阶段发送数据的长度。前面请求第一个字节里,已经说明下一阶段数据传送的方向,这里说明了传送数据的长度,不管是发送数据还是接收数据,都不要超过这个数据长度,在这个获取设备描述符里,它的长度是40 00
,按小端格式解释,就是64
个字节。
二.回应设备描述符
typedef struct
{
u8 bLength; //描述结构体大小
u8 bDescriptorType; //描述符类型
u16 bcdUSB; //USB版本号
u8 bDeviceClass; //设备类代码
u8 bDeviceSubClass; //子类代码
u8 bDeviceProtocol; //设备协议代码
u8 bMaxPacketSize0; //端点0的最大包大小
u16 idVendor; //生产厂商编号
u16 idProduct; //产品编号
u16 bcdDevice; //设备出厂编号
u8 iManufacturer; //设备厂商字符串索引
u8 iProduct; //产品描述字符串索引
u8 iSeriaNumber; //设备序列号字符串索引
u8 bNumConfigurations; //当前速度下载能支持的配置数量
}
返回给主控制器的数据结构就是上面的内容,只要把上面的结构体填写合适的内容,就可以发送给主控制器,12 01 10 01 00 00 00 40 00 80 00 80 00 01 04 2C 4A 01
。
-
bLength
是本结构体的大小,本次返回的结构体长度是0X12
,也就是18
个字节。 -
bDescriptorType
是描述符的类型,它的定义跟主控制器发下来的描述符类型是一样的,如下:DEVICE 1 CONFIGUARTION 2 STRING 3 INTERFACE 4 ENDPOINT 5 DEVICE_QUALIFIER 6 OTHER_SPEED_CONFIGURATION 7 INTERFACE_POWER1 8
由于返回的是设备描述符,所以就选择了
0x01
,用这个类型来区分不同的描述符。 -
bcdUSB
是USB
发布的版本协议,USB1.1
表示为0x0110
. -
bDeviceClass
是设备分类,当它的值是0
时,表示所有接口在配置描述符里,并且所有接口是独立的。当它的值是1
到FEH
时,表示不同的接口关联的。当它的值是FFH
时,它是厂商自己定义的。在这个设备里,它的值为0
. -
bDeviceSubClass
是设备子分类码,当前面的bDeviceClass
值是0
时,这里一定要设置为0
,其他就根据USB-IF
组织定义的编码。 -
bDeviceProtocols
是设备使用的协议,如果使用USB-IF
组织定义的协议,就需要设置这里的值,如果不使用,就直接设置为0
,如果厂商自己定义的可以设置为FFH
,以上三个值,在本设备中全部设置为0
. -
bMaxPacketSize0
是端点0收发最大包的大小,仅允许设置8、16、32、64中的任何一个大小。 -
idVendor
是厂商标识,由USB-IF
分配的编码,这里使用0x8000
. -
idProduct
是厂商定义的产品标识,可以让操作系统加载不同的驱动程序。 -
bcdDevice
是用BCD
表示的设备发布的版本号,这里是1.00
. -
iManufacturer
是厂商字符串的偏移值,这个值主要说明了它在字符串描述符里的偏移位置,如果它设置为0,表示没有厂商字符串,在这里是0x04
. -
iProduct
是产品字符串的偏移值…,在这里是0x2C
. -
iSerialNumber
是序列号字符串的偏移值…,在这里是0x4A
. -
bNumConfigurations
是配置描述符的个数,在这里只使用了一个配置描述符,所以设置为1
.
三.设置USB地址
前面已经解释了主控制器怎样发送设备描述符下来,然后设备返回相应的设备描述符,下一步就是主控制器分配地址给设备,USB
的设备地址是从1
开始到127
,下面就是接收到主控制器发下来的数据包:00 05 01 00 00 00 00 00
.
由USB_SETUP_PACKET
定义具体的分析这个数据,就知道应做什么样的响应了。先取得bmRequestType
的类型,也就是第一个字节,它是00
,从USB
协议里查看,它的方向位是主控制器发送给设备,由bit5和bit6
位可以得知它是USB
协议里定义的标准请求,由bit4-0
位知道它是USB
设备接收这个包数据。
bRequest
是05
,为设置地址SET_ADDRESS
,所以这个包需要按设置地址的格式去解释后面的数据。
wValue
存放USB
的设备地址,因为它的值是01 00
,按小端格式解释就是0x0001
.
USB
的串行引擎通过这个地址来判断是否接收总线上的数据,如果发送的地址跟它一致,就会接收主控制器发过来的数据,当然从这个设备发出去的数据也带有这个地址,因此就可以让主控制器识别不同的USB
设备数据了。
四.配置描述符
在有了设备地址后,主机会再次发送获取上面已经读取的设备描述符:80 06 00 01 00 00 12 00
,然后USB
设备也再次回应它,但这次发送的长度是0x0012
了,不会是第一次64
个字节长度了。接着USB
设备就返回下面的描述符给主控制器,也就是第一次已经发送的设备描述符,如下:12 01 10 01 00 00 00 40 00 80 00 80 00 01 04 2C 4A 01
,这样分配地址之后,再次获取设备描述符成功了。
接着就是主控制器获取配置描述符,下面就是收到的配置描述符数据:80 06 00 02 00 00 09 00
,分析以上数据:
-
bmRequestType:80
,表示方向是从USB
设备发送给主机,接收设备是USB
设备。 -
bRequest:06
,表示获取描述符,GET_DESCRIPTOR
。 -
wValue:00 02
,低字节表示偏移地址00
,高字节表示描述符的类型,CONFIGURATION
,返回的是配置描述符。 -
wIndex:00 00
-
wLength:09 00
,表示返回描述符的长度,这里是9个字节接下来就是设备返回配置描述符给主控制器,发送的数据如下:
09 02 22 00 01 01 00 01 32
,发送的数据是按下面的结构来定义,这也是在USB
协议里定义的格式:typedef struct { u8 bLength; //描述结构体大小 u8 bDescriptorType; //描述符类型 u16 wTotallLength; //配置描述符集合总长度 u8 bNumInterfaces; //配置支持的接口数 u8 bConfigurationValue; //该配置的值 u8 iConfiguartion; //描述该配置的字符串索引值 u8 bmAttributes; //供电模式选择 u8 bMaxPower; //设备需要的最大电源 }
-
bLength
配置的长度,也就是配置结构的整个长度,这里为9字节。 -
bDescriptorType
是描述符的类型,这里是配置描述符,所以设置为02
。 -
wTotallLength
是所有配置设置的结构长度,包括配置描述符、接口描述符、HID
描述符、端点描述符或者其他描述符。这里是22 00
,也就是0x0022
个字节。 -
bNumInterfaces
是接口个数,这里一个。 -
bConfigurationValue
是配置的个数,当设置配置时发送的值,这个设置为1
个配置。 -
iConfiguration
是说明配置的字符的偏移,这里是0
。 -
bMAttributes
是配置特性,D7
位保留,D6
位是说明是否自供电,D5
位是否支持远程唤醒,D4-D0
是保留。 -
bMaxPower
是使用的功率,它采用电流来表示,每2mA
为单位,通过这样的说明,主控制器就知道这个设备是什么样的的设备,有多少功能。
五.字符串描述符
如果在设备描述符那里指定没有字符串描述符的话,在这里是不会收到字符串描述符的,由于我在设备描述符里有字符串描述符的偏移地址,因此,就收到主控制器发出请求字符串描述符,收到的数据如下:
80 06 00 03 00 00 FF 00
。-
bmRequestType:80
表示方向是从USB
设备发送给主控制器,接收设备是USB
设备。 -
bRequest:06
表示这是获取描述符,GET_DESCRIPTOR
。 -
wValue:00 03
,低字节表示偏移地址00
,高字节表示描述符的类型STRING
。 -
wIndex:00 00
-
wLength:FF 00
,它表示返回描述符的长度,这里是256
个字节。因此,这个获取字符串描述符,就是从字符串描述符内存里,0偏移地址开始的位置读取第一个字符串描述符返回给主控制器。接着就返回下面的数据给主控制器:
04 03 09 04
。typedef struct { u8 bLength; u8 bDescriptorType; u16 bString; }
-
bLength
是所有数据的长度,这里为4。 -
bDescriptorType
是描述类型,这里字符串描述符,所以这是3. -
bString
是可变的字符串数组,不超过254个都应该是可以的,并且它是使用UNICODE编码的字符串,在这里09 04
,这是美国英语的标识,0x0409
。如果想输入中文的标识,只要改为0x0804
就可以了。通过这个字符串描述符,主控制器就知道字符串描述符是使用什么语言说明的了,这样就可以支持全世界的语言标识。
原文链接:https://www.cnblogs.com/Daniel-G/p/3993883.html
-
-