USB描述符異步
USB描述符信息存儲在USB設備中,在枚舉過程當中,USB主機會向USB設備發送GetDescriptor請求,USB設備在收到這個請求以後,會將USB描述符信息返回給USB主機,USB主機分析返回來的數據,判斷出該設備是哪種USB設備,創建相應的數據連接通道。那麼USB描述符信息究竟是一個什麼樣的數據呢,USB協議中有詳細描述。大數據
通用的USB描述符信息包括設備描述符、配置描述符、接口描述符和端點描述符,具體不一樣的USB設備還包括其它類型的描述符,例如,USB鼠標、鍵盤還包括HID描述符和報告描述符,還有可能包括字符串描述符,USB協議中對描述符類型定義以下:.net
全部的描述符信息都是經過發送GetDescriptor請求獲得的,可是USB設備也不知道你要獲取的是哪一種描述符,因此還須要在GetDescriptor請求中指定描述符的類型以及描述符的長度,這樣USB設備才能正確的返回描述符信息。orm
1 設備描述符blog
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個字節。ip
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最大數據包長度,必須爲八、1六、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/