枚舉能夠理解爲主機按不定的順序向USB設備討要設備信息,好給它分配資源,若枚舉不成功,就放棄分配資源,省得浪費資源。通常都是使用中斷傳輸方式通訊。異步
經常使用的描述符有如下幾種:01H、設備描述符 02H、配置描述符 03H、字符串描述符 04H、接口描述符 05H、端點描述符工具
21H:HID描述符 22H:HID報告學習
一個設備只能有一個設備描述符,而一個設備描述符能夠包含多個配置描述符(bNumConfigurations ),一個配置描述符又能夠包含多個接口描述符,一個接口使用了幾個端點,就有幾個端點描述符。網站
如下爲HID描述符:(一個USB設備同時包含鍵盤和鼠標,使用2個接口)編碼
1、設備描述符:Device descriptorspa
hid_device_descriptor =
{操作系統
0x12 , // bLength 該段描述符總長18個,不可變
0x01, // bDescriptorType:經常使用的以下0x01:設備 0x02配置 0x03字符 0x04接口 0x05端點 0x21HID
0x0200, // bcdUSB USB版本號: 1.1--0x0110 2.0--0x0200 3.0--0x0300
0x00, // bDeviceClass HID 不使用接口聯合描述字與下面一塊兒設置爲00H
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
8, // bMaxPacketSize0 端點0最大包的大小 USB2.0:低速--8 全速:八、1六、3二、64 高速:64
0x1223, // idVendor VID
0x3F07, // idProduct PID
0x1110, // bcdDevice 廠商指定的設備版本號
0x01, // iManufacturer 指向描述製造商字符串的索引
0x02, // iProduct 指向描述產品的字符串索引
0x00, // iSerialNumber 指向設備序列號的字符串索引
0x01 // bNumConfigurations 定義配置描述符的數量
};對象
2、配置描述符索引
hid_configuration_descriptor =接口
{
0x09, // bLength 長度9個,不可變
0x02, // bDescriptorType 配置描述符
0x3b00, // wTotallength= 9+(9+9+7)+(9+9+7) 配置描述符+(接口描述符+HID描述符+端點描述符)*接口數
配置描述符信息總的大小,包括接口描述符、端點描述符等等
0x02, // bNumInterfaces 接口數量=2(鍵盤+鼠標)
0x01, // bConfigurationValue Set_Configuration命令須要的參數值
0x00, // iConfiguration 配置字符串索引
0xa0, // bmAttributes bit7=1 bit6:1--自供電 0--總線供電 bit5:1--遠程喚起 0--不支持 bit[4:0]=0
0x32 // MaxPower (in 2mA units) 50*2mA=100mA
};
3、接口配置符
keyboard_interface_descriptor =
{
0x09, // bLength 長度9個,不可變
0x04, // bDescriptorType 接口描述符
0x00, // bInterfaceNumber 接口0 (接口從0開始,鍵盤定義0,鼠標定義1)
0x00, // bAlternateSetting 接口索引值
0x01, // bNumEndpoints 端點個數1(端點0不可用,好比EP1)
0x03, // bInterfaceClass (3 = HID)
0x01, // bInterfaceSubClass 接口子類型:01爲Boot Device,鍵鼠在BIOS下就啓動
0x01, // bInterfaceProcotol 接口協議:00--None 01--Keyboard 02--Mouse
0x00 // iInterface 描述該接口的字符串索引
};
mouse_interface_descriptor =
{
0x09, // bLength 長度9個,不可變
0x04, // bDescriptorType 接口描述符
0x01, // bInterfaceNumber 接口1 不一樣接口
0x00, // bAlternateSetting 接口索引值
0x01, // bNumEndpoints 端點個數1(端點0不可用,好比EP2)
0x03, // bInterfaceClass (3 = HID)
0x01, // bInterfaceSubClass 接口子類型:01爲Boot Device,鍵鼠在BIOS下就啓動
0x02, // bInterfaceProcotol 接口協議:00--None 01--Keyboard 02--Mouse
0x00 // iInterface 描述該接口的字符串索引
};
4、HID描述符
keyboard_hid_descriptor =
{
0x09, // bLength 長度9個,不可變
0x21, // bDescriptorType HID描述符
0x0110, // bcdHID HID專屬版本號
0x00, // bCountryCode 國家代碼
0x01, // bNumDescriptors 附屬類描述字的數目1個
0x22, // bDescriptorType 描述字類型:報告
HID_KEYBOARD_REPORT_DESCRIPTOR_SIZE // 鍵盤HID報告描述字總字節數,好比:0x75,0x00,低字節在前
};
mouse_hid_descriptor =
{
0x09, // bLength 長度9個,不可變
0x21, // bDescriptorType HID描述符
0x0110, // bcdHID HID專屬版本號
0x00, // bCountryCode 國家代碼
0x01, // bNumDescriptors 附屬類描述字的數目1個
0x22, // bDescriptorType 描述字類型:報告
HID_MOUSE_REPORT_DESCRIPTOR_SIZE // 鼠標HID報告描述字總字節數,好比0x34, 0x00,低字節在前
};
5、端點描述符
hid_keyboard_endpoint1_in_descriptor =
{
0x07, // bLength 長度7個,不可變
0x05, // bDescriptorType 端點描述符
0x81, // bEndpointAddress bit[7]:1--IN 0--OUT 地址爲EP1,輸入
0x03, // bmAttributes 傳輸類型(中斷--03H)
0x08, // MaxPacketSize_LSB 端點1最大信息包尺寸
0x00, // MaxPacketSize_MSB
0x08, // bInterval 輪詢間隔 一幀爲8箇中斷間隔
};
hid_mouse_endpoint2_in_descriptor =
{
0x07, // bLength 長度7個,不可變
0x05, // bDescriptorType 端點描述符
0x82, // bEndpointAddress bit[7]:1--IN 0--OUT 地址爲EP2,輸入
0x03, // bmAttributes 傳輸類型(中斷--03H)
0x08, // MaxPacketSize_LSB 端點1最大信息包尺寸
0x00, // MaxPacketSize_MSB
0x08, // bInterval 輪詢間隔 一幀爲8箇中斷間隔
};
說完上述幾個重要描述符後,咱們再來看字符串描述符.
在USB中,字符串描述符是可選的,也就是無關緊要的角色,USB並無強制規定必須有,可是通常產品是有的,至少能說明生產廠家,產品信息等,要否則這個產品看誰還敢用.哈哈哈...
若是設備沒有字符串描述符,那麼在設備描述符、配置描述符、接口描述符等處的字符串索引值必須爲0,要否則在枚舉過程當中,USB主機會嘗試去獲取字符串描述符,而恰好你又沒有,那麼枚舉就會失敗,因此必須指定爲0
字符串描述符使用UNICODE編碼,能夠支持多種語言,因此字符串描述符首先要指定語言ID,語言ID代碼能夠參考這個網站:http://www.usb.org/developers/docs/USB_LANGIDs.pdf,例如:簡體中文的ID值爲0x0804,美式英語ID值爲0x0409。
語言ID字符串描述符結構定義以下:
在枚舉過程當中,USB主機會向USB設備發送GET_DESCRIPTOR請求,同時wValue字段高字節爲描述符類型,字符串描述符的類型爲0x03,低字節爲字符串描述符索引值,對於語言ID的索引爲0,其它字符串描述符索引由設備描述符指定,wIndex字段爲語言ID。
字符串描述符結構定義以下:
bLength爲描述符長度,bDescriptorType爲描述符類型,字符編碼統一採用UNICODE編碼,UNICODE採用兩個字節字節表示一個字符,若是是英語字符的話,那就很簡單了,直接在ASCII碼前面補上一個爲0x00的字節數據就組成UNICODE編碼了,若是是其它語言的話,網上有不少的UNICODE編碼轉換工具,能夠直接拿來使用就好了。
最後補上個人USB鼠標字符串描述符信息。
語言ID信息:
廠商字符串描述符以下:
我在Virtual Box中捕獲的信息,因此廠商字符串爲VirtualBox。
產品字符串描述符信息以下:
主機經過標準請求命令來得到以上HID描述符和HID報告:
標準USB設備請求命令共有11個,大小都是8個字節,具備相同的結構,由5 個字段構成(字段是標準請求命令的數據部分),結構以下(括號中的數字表示字節數,首字母bm,b,w分別表示位圖、字節,雙字節):
bmRequestType(1) +bRequest(1) +wvalue(2) +wIndex(2) +wLength(2)
1、bmRequestType:
bit[7]: 說明請求的傳輸方向 1--設備到主機(IN) 0--主機到設備(OUT)
bit[6:5]:00--標準請求命令 01--專門類請求 10--用戶定義的請求 11--保留
bit[4:0]:00000--接收者爲設備 00001--接收者爲接口 00010--接收者爲端點 00011--接收者爲其餘元件 其餘設置保留
2、bRequest:
請求命令代碼,在標準的USB命令中,每個命令都定義了編號,編號的值就爲字段的值,編號與命令名稱以下(要注意這裏的命令代碼要與其餘字段結合使用,能夠說命令代碼是標準請求命令代碼的核心,正是由於這些命令代碼而決定了11個USB標準請求命令):
一、Get Status (00H) 獲取狀態
wValue:0000H wIndex:0000H(設備)、接口號或端點號 wLength:0002H
A:[To Device]獲取設備的狀態:
位0:自供電(0表示總線供電;1表示自供電).
位1:遠程喚醒(0表示不支持遠程喚醒;1表示遠程喚醒).
位2~15:保留.
通常選擇總線供電,不支持遠程喚醒,因此返回數據就是0x0000.
B:[To Interface]獲取接口的狀態:
接口狀態的16位字節所有保留,因此返回數據就是0x0000.
C:[To Endpoint]獲取端點的狀態:
位0:Halt(0表示端點容許;1表示端點禁止).
位1~15:保留(復位爲0).
二、Clear Feature (01H) 清除特性
wValue:所要禁用的特徵 wIndex:0000H(設備)、接口號或端點號 wLength:0000H
A:[To Device]清除設備的遠程喚醒功能,並返回一個空包.
B:[To Endpoint]解禁端點.
3、Set Feature (03H) 設置特性
wValue:所要使能的特徵 wIndex:0000H(設備)、接口號或端點號 wLength:0000H
A:[To Device]設置設備的遠程喚醒功能,並返回一個空包.
B:[To Endpoint]禁止端點.
四、Set Address (05H) 設置地址
wValue:新的設備地址,範圍0001H到007FH wIndex:0000H wLength:0000H
A:設置設備地址.
五、Get Descriptor (06H) 獲取描述符
wValue:高字節--描述符類型 低字節--描述符索引 wIndex:0000H或ID wLength:需返回的字節數
A:[To Device]獲取設備描述符:
描述當前USB協議的版本號.設備端點0的FIFO大小.USB設備的ID號等.
B:[To Configuration]獲取配置描述符:
描述USB設備接口個數及是否有自供電能力等.
C:[To Interface]獲取接口描述符:
描述端點0之外的物理端點個數等信息.
D:[To Endpoint]獲取端點描述符:
描述端點0各端點的傳輸類型和最大信息包大小和端點的傳輸方向(IN/OUT).
六、Set Descriptor (07H) 設置描述符(可選,沒法更新)
wValue:高字節--描述符類型 低字節--描述符索引 wIndex:0000H或ID wLength:需傳輸給設備的字節數
七、Get Configuration (08H) 獲取配置信息
wValue:0000H wIndex:0000H wLength:0001H
八、Set Configuration (09H) 設置配置
wValue:低字節規定了一個配置,若此值與設備支持的配置匹配,設備將實現所請求配置 wIndex:0000H wLength:0000H
A:[To Configuration]設置配置描述符.
B:[To Interface]設置接口描述符.
C:[To Endpoint]設置端點描述符.
九、Get Interface (0AH) 獲取接口信息
wValue:0000H wIndex:接口號(bInterfaceNumber) wLength:0001H
十、Set Interface (0BH) 設置接口
wValue:要選擇的替代設置(bAlternateSetting) wIndex:接口號(bInterfaceNumber) wLength:0000H
十一、SYNCH_FRAME(0CH)
wValue:0000H wIndex:0000H wLength:0006H
用於設備設置和報告一個端點的同步幀.
一個描述設備描述符和描述配置描述符過程以下圖:
HID設備描述符
溫習了以上內容,咱們再來看看HID協議與這些描述符之間的關係。
當插入USB設備後,主機會向設備請求各類描述符來識別設備。
爲了把一個設備識別爲HID類別,設備在定義描述符的時候必須遵照HID規範。
從框圖中,能夠看出除了USB標準定義的一些描述符外,HID設備還必須定義HID描述符。另外設備和主機的通訊是經過報告的形式來實現的,因此還必須定義報告描述符;而物理描述符不是必需的。還有就是HID描述符是關聯於接口(而不是端點)的,因此設備不須要爲每一個端點都提供一個HID描述符。
接口描述符中bInterfaceClass的值必須爲0x03,bInterfaceSubClass的值爲0或1,爲1表示HID設備符是一個啓動設備(Boot Device,通常對PC機而言纔有意義,意思是BIOS啓動時能識別並使用您的HID設備,且只有標準鼠標或鍵盤類設備才能成爲Boot Device。若是爲0則只有在操做系統啓動後才能識別並使用您的HID設備)。
USB HID類描述符的結構 |
||||
偏移量 |
域 |
大小 |
值 |
描述 |
0 |
bLength |
1 |
數字 |
此描述符的長度(以字節爲單位) |
1 |
bDescriptorType |
1 |
常量 |
描述符種類(此處爲0x21即HID類描述符) |
2 |
bcdHID |
2 |
數字 |
HID規範版本號(BCD碼),採用4個16進制的BCD格式編碼,如版本1.0的BCD碼爲0x0100,版本爲1.1的BCD碼爲0x0110 |
4 |
bCountryCode |
1 |
數字 |
硬件目的國家的識別碼(BCD碼)(見表3) |
5 |
bNumDescritors |
1 |
數字 |
支持的附屬描述符數目 |
6 |
bDescriptorType |
1 |
常量 |
HID相關描述符的類型 0x21:HID描述符 0x22:報告描述符 0x23:物理描述符 |
7 |
wDescriptorLength |
2 |
數字 |
報告描述符總長度 |
9 |
bDescriptorType |
1 |
常量 |
用於識別描述符類型的常量,使用在有一個以上描述符的設備 |
10 |
wDescriptorLength |
2 |
數字 |
描述符總長度,使用在有一個以上描述符的設備 |
報告描述符
報告描述符比較複雜,它是以item形式排列組合而成,無固定長途,用戶能夠自定義長度以及每一bit的含義。item類型分三種:main,global和local,其中main類型又可分爲5種tag:
每個main item tag(input,output,feature)都代表了來自一個特定管道的數據的大小,數據相對仍是獨立,以及其餘相關信息。在此以前,global和local item定義了數據的最大值和最小值,等等。local item僅僅描述下一個main item定義的數據域,而global item是這一個報告描述符中全部後續數據段的默認屬性。
一個報告描述符可能包含多個main item,爲了準確描述來自一個控制管道的數據,一個報告描述符必須包括如下內容:
下面用一個三鍵鼠標舉例說明:
Usage Page (Generic Desktop); //global item
Usage (Mouse); //global item
Collection (Application); //Start Mouse collection
Usage (Pointer); //
Collection (Physical); //Start Pointer collection
Usage Page (Buttons)
Usage Minimum (1),
Usage Maximum (3),
Logical Minimum (0),
Logical Maximum (1) ; //Fields return values from 0 to 1
Report Count (3),
Report Size (1); //Create three 1 bit fields (button 1, 2, & 3)
Input (Data, Variable, Absolute); //Add fields to the input report.
Report Count (1),
Report Size (5); //Create 5 bit constant field
Input (Constant), ;Add field to the input report
Usage Page (Generic Desktop),
Usage (X),
Usage (Y),
Logical Minimum (-127),
Logical Maximum (127); //Fields return values from -127 to 127
Report Size (8),
Report Count (2); //Create two 8 bit fields (X & Y position)
Input (Data, Variable, Relative); //Add fields to the input report
End Collection; //Close Pointer collection
End Collection; //Close Mouse collection
item的數據格式有兩種,分別是短item和長item。
短item格式
bSize | 0:0個字節 1:1個字節 2:2個字節 3:4個字節 |
bType | 0:main 1:global 2:local 3:保留 |
bTag | item類型 8:input 9:output A:collection B:feature C:end collection |
長item,其bType位值爲3,bTag值爲F
bDataSize | 0:0個字節 1:1個字節 2:2個字節 3:4個字節 |
bLongItemTag | 0:main 1:global 2:local 3:保留 |
data | 數據 |
物理描述符用來描述行爲特性,是可選的。
USB HID類可採用的通訊管道
全部的HID設備經過USB的控制管道(默認管道,即端點0)和中斷管道與主機通訊。
控制管道主要用於如下3個方面:
接收/響應USB主機的控制請示及相關的類數據
在USB主機查詢時傳輸數據(如響應Get_Report請求等)
接收USB主機的數據
中斷管道主要用於如下兩個方面:
USB主機接收USB設備的異步傳輸數據
USB主機發送有實時性要求的數據給USB設備
從USB主機到USB設備的中斷輸出數據傳輸是可選的,當不支持中斷輸出數據傳輸時,USB主機經過控制管道將數據傳輸給USB設備。
表一、USB HID規範定義的HID設備可用端點 |
||
管道 |
要求 |
說明 |
控制(端點0) |
必須 |
傳輸USB描述符、類請求代碼以及供查詢的消息數據等 |
中斷輸入 |
必須 |
傳輸從設備到主機的輸入數據 |
中斷輸出 |
可選 |
傳輸從主機到設備的輸出數據 |
HID設備6種特定請求
HID類請求(命令)包格式 |
|||
偏移量 |
域 |
大小 |
說明 |
0 |
bmRequestType |
1 |
HID設備類請求特性以下: 於是,針對HID的設備類請求,僅僅10100001和00100001有效 |
1 |
bRequest |
1 |
HID類請求(參考下表) |
2 |
wValue |
2 |
高字節說明描述符的類型 0x21:HID描述符 0x22:報告描述符 0x23:物理描述符 低字節爲非0值時被用來選定實體描述符。 |
4 |
wIndex |
2 |
2字節數值,根據不一樣的bRequest有不一樣的意義 |
6 |
wLength |
2 |
該請求的數據段長度 |
HID類請求 |
||
數值 |
HID類請求描述符 |
註釋 |
0x01 |
GET_REPORT |
主機用控制傳輸從設備接收數據,全部HID類設備都要支持這個請求; |
0x02 |
GET_IDLE |
主機讀取設備當前的空閒速率,設備能夠不支持此請求; |
0x03 |
GET_PROTOCOL |
僅僅適應於支持啓動功能的HID設備(Boot Device) |
0x09 |
SET_REPORT |
設備用控制傳輸接收主機的數據,設備能夠不支持此請求; |
0x0A |
SET_IDLE |
設置閒置狀態,設備可不支持此請求; |
0x0B |
SET_PROTOCOL |
僅僅適應於支持啓動功能的HID設備(Boot Device) |
GET_REPORT:主機經過控制端點獲取一個Report
域 |
值 |
描述 |
bmRequestType |
0xA1 |
|
bRequest |
0x01 |
|
wValue |
高字節表示報告類型 0x01:input 0x02:output 0x03:feature other:reserved 低字節表示ReportID,如不使用設爲0 |
|
wIndex |
HID的interface索引值 |
|
wLength |
Report長度 |
|
Data |
Report內容 |
|
SET_REPORT:主機發送一個Report給設備,用以設置input,output或者feature
域 |
值 |
描述 |
bmRequestType |
0x21 |
|
bRequest |
0x09 |
|
wValue |
高字節表示報告類型 0x01:input 0x02:output 0x03:feature other:reserved 低字節表示ReportID,如不使用設爲0 |
|
wIndex |
HID的interface索引值 |
|
wLength |
Report長度 |
|
Data |
Report內容 |
|
GET_IDLE
域 |
值 |
描述 |
bmRequestType |
0xA1 |
|
bRequest |
0x02 |
|
wValue |
高字節0 低字節表示ReportID,如不使用設爲0 |
|
wIndex |
HID的interface索引值 |
|
wLength |
1 |
|
Data |
空閒速率 |
|
SET_IDLE
域 |
值 |
描述 |
bmRequestType |
0x21 |
|
bRequest |
0x0A |
|
wValue |
新的速率 低字節表示ReportID,如不使用設爲0 |
|
wIndex |
HID的interface索引值 |
|
wLength |
0 |
|
Data |
無 |
|
GET_PROTOCOL
域 |
值 |
描述 |
bmRequestType |
0xA1 |
|
bRequest |
0x03 |
|
wValue |
0 |
|
wIndex |
HID的interface索引值 |
|
wLength |
1 |
|
Data |
0 = Boot Protocol 1 = Report Protocol |
|
SET_PROTOCOL
域 |
值 |
描述 |
bmRequestType |
0x21 |
|
bRequest |
0x0B |
|
wValue |
0 = Boot Protocol 1 = Report Protocol |
|
wIndex |
HID的interface索引值 |
|
wLength |
0 |
|
Data |
無 |