您的位置:首页 > 其它

USB描述符

2016-04-18 10:16 351 查看
USB描述符
USB描述符信息存储在USB设备中,在枚举过程中,USB主机会向USB设备发送GetDescriptor请求,USB设备在收到这个请求之后,会将USB描述符信息返回给USB主机,USB主机分析返回来的数据,判断出该设备是哪一种USB设备,建立相应的数据链接通道。那么USB描述符信息到底是一个什么样的数据呢,USB协议中有详细描述。

通用的USB描述符信息包括设备描述符、配置描述符、接口描述符和端点描述符,具体不同的USB设备还包括其它类型的描述符,例如,USB鼠标、键盘还包括HID描述符和报告描述符,还有可能包括字符串描述符,USB协议中对描述符类型定义如下:



所有的描述符信息都是通过发送GetDescriptor请求得到的,但是USB设备也不知道你要获取的是哪种描述符,所以还需要在GetDescriptor请求中指定描述符的类型以及描述符的长度,这样USB设备才能正确的返回描述符信息。

1 设备描述符
Linux中对于设备描述符结构体定义如下:

216 /* USB_DT_DEVICE: Device descriptor */

217 struct usb_device_descriptor {

218 __u8 bLength;

219 __u8 bDescriptorType;

220

221 __le16 bcdUSB;

222 __u8 bDeviceClass;

223 __u8 bDeviceSubClass;

224 __u8 bDeviceProtocol;

225 __u8 bMaxPacketSize0;

226 __le16 idVendor;

227 __le16 idProduct;

228 __le16 bcdDevice;

229 __u8 iManufacturer;

230 __u8 iProduct;

231 __u8 iSerialNumber;

232 __u8 bNumConfigurations;

233 } __attribute__ ((packed));

234

235 #define USB_DT_DEVICE_SIZE 18

bLength: 描述符的长度,设备描述符的长度为18个字节。
bDescriptorType: 描述符的类型,设备描述符的类型为0x01。
bcdUSB: USB设备所遵循的协议版本号,例如2.0协议为0x0200。
bDeviceClass: USB设备类代码,由USB-IF分配,如果该字段为0x00,表示由接口描述符来指定(有可能该USB设备是一个复合设备,USB设备的各个接口相互独立,分别属于不同的设备类)。如果是0x01~0xfe,表示为USB-IF定义的设备类,例如0x03为HID设备,0x09为HUB设备。如果是0xff,表示由厂商自定义设备类型。
bDeviceSubClass: USB子类代码,由USB-IF分配,如果bDeviceClass为0x00,那么该字段也必须为 0x00,其它情况可以参考USB关于对于USB Device Class的定义。
bDeviceProtocol: 协议代码,由USB-IF分配,如果bDeviceClass和bDeviceSubClass定义为0x00,那么该字段也必须为0x00。
bMaxPacketSize0: 端点0最大数据包长度,必须为8、16、32和64。
idVendor: 厂商ID,由USB-IF分配,需要向USB-IF组织申请。
idProduct: 产品ID,由厂商指定。
bcdDevice: 设备序列号,由厂商自行设置。
iManufacturer: 用于描述厂商的字符串描述符索引。
iProduct: 用于描述产品的字符串描述符索引。
iSerialNumber: 用于描述产品序列号的字符串描述符索引,注意,所有的字符串描述符是可选的,如果没有字符串描述符,指定这些索引为0x00。
bNumConfigurations:配置描述符数量。
例如,我的USB鼠标设备描述符信息如下:



从中可以看出该USB设备符合USB1.1协议,在设备描述中并没有指定该USB设备类型,端点0最大数据包长度为8个字节,也就是说一次还不能获取完全设备描述符,需要三次才能获取完全。再看bMaxPacketSize0在设备描述符中的偏移,刚好是第8个字节,也就是说传输一次就能知道端点0一次能够传输多长的数据,根据这个值才能判断出是否继续传输,来完整的获取描述符信息。该USB设备的idVendor为0x80ee,idProduct为0x0021,有一个配置等等信息。

2 配置描述符
一个USB设备只有一个USB设备描述符,可以有多个配置描述符,配置描述符定义如下:

265 /* USB_DT_CONFIG: Configuration descriptor information.

266 *

267 * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the

268 * descriptor type is different. Highspeed-capable devices can look

269 * different depending on what speed they're currently running. Only

270 * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG

271 * descriptors.

272 */

273 struct usb_config_descriptor {

274 __u8 bLength;

275 __u8 bDescriptorType;

276

277 __le16 wTotalLength;

278 __u8 bNumInterfaces;

279 __u8 bConfigurationValue;

280 __u8 iConfiguration;

281 __u8 bmAttributes;

282 __u8 bMaxPower;

283 } __attribute__ ((packed));

284

285 #define USB_DT_CONFIG_SIZE 9

bLength: 配置描述符长度,配置描述符长度为9字节大小。
bDescriptorType: 描述符类型,配置描述符类型为0x02。
wTotalLength: 配置描述符信息总的大小,包括接口描述符、端点描述符等等。
bNumInterfaces: USB接口数量。
bConfigurationValue: 当使用SetConfiguration和GetConfiguration请求时所指定的配置索引值。
iConfiguration: 描述配置的字符串描述符索引。
bmAttributes: 供电配置,位详细定义如下:
D7 保留,必须置1
D6 自供电模式
D5 远程唤醒
D4~D0 保留
bMaxPower: 最大功耗,以2mA为单位,例如0x32为50*2=100mA。
我的USB鼠标配置描述符信息如下:



从中可以看出该设备配置信息总大小为0x22=34字节大小,有一个接口,最大功耗为100mA等信息。

3 接口描述符
一个配置中可以有一个或多个接口,一个接口中有0个或多个端点,接口描述符和端点描述符不能直接通过GetDescriptor请求返回,必须连同配置描述符一起返回,Linux中接口描述符定义如下:

309 /* USB_DT_INTERFACE: Interface descriptor */

310 struct usb_interface_descriptor {

311 __u8 bLength;

312 __u8 bDescriptorType;

313

314 __u8 bInterfaceNumber;

315 __u8 bAlternateSetting;

316 __u8 bNumEndpoints;

317 __u8 bInterfaceClass;

318 __u8 bInterfaceSubClass;

319 __u8 bInterfaceProtocol;

320 __u8 iInterface;

321 } __attribute__ ((packed));

322

323 #define USB_DT_INTERFACE_SIZE 9

bLength: 描述符长度,接口描述符长度为9个字节。
bDescriptorType: 描述符类型,接口描述符的类型为0x04。
bInterfaceNumber: 该接口编号,接口编号从0开始分配,当一个配置有多个接口时,就用该字段来区分不同的接口。
bAlternateSetting:
bNumEndpoints: 端点数量,不包括端点0。
bInterfaceClass
bInterfaceSubClass
bInterfaceProtocol: 和设备描述符中的bDeviceClass、bDeviceSubClass、bDeviceProtocol类似。
iInterface: 描述该接口的字符串描述符索引。
接口描述符实例如下:



前面9个字节是配置描述符,从中可以看出端点数量为1,bInterfaceClass为0x03,即为HID设备。

4 端点描述符
注意,端点0没有端点描述符,Linux中端点描述符结构定义如下:

327 /* USB_DT_ENDPOINT: Endpoint descriptor */

328 struct usb_endpoint_descriptor {

329 __u8 bLength;

330 __u8 bDescriptorType;

331

332 __u8 bEndpointAddress;

333 __u8 bmAttributes;

334 __le16 wMaxPacketSize;

335 __u8 bInterval;

336

337 /* NOTE: these two are _only_ in audio endpoints. */

338 /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */

339 __u8 bRefresh;

340 __u8 bSynchAddress;

341 } __attribute__ ((packed));

342

343 #define USB_DT_ENDPOINT_SIZE 7

344 #define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */

bLength: 描述符长度,这里有两个值如果是audio设备的端点,那么端点描述符长度就为9个字节,对于其它设备端点,端点描述符长度就为7个字节。
bDescriptorType: 描述符类型,端点描述符类型为0x05。
bEndpointAddress: 端点地址,详细定义如下:
D7 端点方向
0 OUT端点
1 IN端点
D6~D4 保留
D3~D0 端点编号
bmAttributes: 端点类型,详细定义如下:
D5~D4 用途
00 数据端点
01 反馈端点
10 隐式反馈数据端点
11 保留
D3~D2 同步类型
00 非同步
01 异步
10 自适应
11 同步
D1~D0 传输类型
00 控制传输
01 同步传输
10 块传输
11 中断传输
如果该端点不是同步端点,D5~D2保留且必须置0。
wMaxPacketSize: 端点所支持最大数据包的长度,详细定义如下:
D10~D0 最大数据包长度
D12~D11
其余位保留且必须置0。
bInterval:端点数据传输的访问时间间隔。对于全速/低速的中断端点,取值范围为 1~255,对于高速中断端点,取值范围为1~16,详细定义可以参考USB协议。
端点描述符实例如下:



因为不能单独的获取接口和端点描述符,所以我将设备配置信息全获取下来了,端点描述符从0x07处开始,0x07为端点描述符长度,该端点是一个IN端点,端点地址为1,该端点是一个中断端点,最大数据包长度为6个字节,时间间隔为10ms。

5 HID描述符
从上图可以看出,除了配置描述符、接口描述符、端点描述符之外、还有一个描述符,它就是HID描述符,HID描述符专用于HID类设备。Linux关于HID描述符结构定义如下:

537 struct hid_class_descriptor {

538 __u8 bDescriptorType;

539 __le16 wDescriptorLength;

540 } __attribute__ ((packed));

541

542 struct hid_descriptor {

543 __u8 bLength;

544 __u8 bDescriptorType;

545 __le16 bcdHID;

546 __u8 bCountryCode;

547 __u8 bNumDescriptors;

548

549 struct hid_class_descriptor desc[1];

550 } __attribute__ ((packed));

bLength: 描述符长度。
bDescriptorType:描述符类型,HID描述符的类型为0x21。
bcdHID: 所遵循的HID协议版本。
bCountryCode: 国家代码。
bNumDescriptors: 下级描述符数量,通常至少需要一个报告描述符。
bDescriptorType: 下级描述符类型,例如报告描述符。
wDescriptorLength: 下级描述符长度。
从上面USB鼠标配置描述符中可以看出,该鼠标所遵循的HID协议版本为1.1,有一个HIDclass描述符,描述符类型为0x22,即报告描述符,描述符长度为0x46。
原文地址:http://blog.csdn.net/mcgrady_tracy/

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: