USB描述符解析-->枚舉.


 枚舉可以理解為主機按不定的順序向USB設備討要設備信息,好給它分配資源,若枚舉不成功,就放棄分配資源,免得浪費資源。一般都是使用中斷傳輸方式通信。

    常用的描述符有以下幾種:01H、設備描述符  02H、配置描述符  03H、字符串描述符  04H、接口描述符  05H、端點描述符

21H:HID描述符 22H:HID報告

    一個設備只能有一個設備描述符,而一個設備描述符可以包含多個配置描述符(bNumConfigurations  ),一個配置描述符又可以包含多個接口描述符,一個接口使用了幾個端點,就有幾個端點描述符。

以下為HID描述:(一個USB設備同時包含鍵盤和鼠標,使用2個接口)

一、設備描述符:Device descriptor

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  全速:8、16、32、64  高速:64
   0x1223,                    // idVendor     VID
   0x3F07,                    // idProduct     PID
   0x1110,                     // bcdDevice   廠商指定的設備版本號
   0x01,                         // iManufacturer  指向描述制造商字符串的索引
   0x02,                         // iProduct           指向描述產品的字符串索引
   0x00,                         // iSerialNumber  指向設備序列號的字符串索引
   0x01                          // bNumConfigurations  定義配置描述符的數量
};

二、配置描述符

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
};

三、接口配置符

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                  描述該接口的字符串索引
};

四、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,低字節在前       
};

五、端點描述符

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)
一、bmRequestType:

        bit[7]: 說明請求的傳輸方向  1--設備到主機(IN)   0--主機到設備(OUT)

        bit[6:5]:00--標准請求命令    01--專門類請求   10--用戶定義的請求    11--保留

        bit[4:0]:00000--接收者為設備   00001--接收者為接口   00010--接收者為端點  00011--接收者為其他元件 其他設置保留

二、bRequest:

      請求命令代碼,在標准的USB命令中,每一個命令都定義了編號,編號的值就為字段的值,編號與命令名稱如下(要注意這里的命令代碼要與其他字段結合使用,可以說命令代碼是標准請求命令代碼的核心,正是因為這些命令代碼而決定了11個USB標准請求命令):
    1、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).

      
    2、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]禁止端點.


    4、Set Address (05H) 設置地址 

      wValue:新的設備地址,范圍0001H到007FH   wIndex:0000H  wLength:0000H
       A:設置設備地址.


    5、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).


    6、Set Descriptor (07H) 設置描述符(可選,無法更新) 

    wValue:高字節--描述符類型  低字節--描述符索引   wIndex:0000H或ID  wLength:需傳輸給設備的字節數


    7、Get Configuration (08H) 獲取配置信息 

    wValue:0000H   wIndex:0000H   wLength:0001H


    8、Set Configuration (09H) 設置配置 

    wValue:低字節規定了一個配置,若此值與設備支持的配置匹配,設備將實現所請求配置   wIndex:0000H  wLength:0000H
       A:[To Configuration]設置配置描述符.
       B:[To Interface]設置接口描述符.
       C:[To Endpoint]設置端點描述符.


    9、Get Interface (0AH) 獲取接口信息    
    wValue:0000H   wIndex:接口號(bInterfaceNumber)  wLength:0001H


    10、Set Interface (0BH) 設置接口 

    wValue:要選擇的替代設置(bAlternateSetting)   wIndex:接口號(bInterfaceNumber)  wLength:0000H


    11、SYNCH_FRAME(0CH)

    wValue:0000H   wIndex:0000H  wLength:0006H
        用於設備設置和報告一個端點的同步幀.

一個描述設備描述符和描述配置描述符過程如下圖:

USB學習之描述符篇--枚舉 - lastnight1034 - lastnight1034的博客
可以看到80  06  00  01  00  00  12  00主機發給設備的請求:
bmRequestType=80H說明這是主機發給設備的標准請求;
bRequest=06H說明這句的作用是Get Descriptor
wValue=0100H(注意這是小端模式,高字節在圖片里顯示在后)說明需要設備上傳設備描述符(01)
wLength=0012H(注意這是小端模式,高字節在圖片里顯示在后)說明設備必須上傳12H個字節長度的數據
於是設備上傳了0012H長的設備描述符:12  01  00  02  00  00  00  08  23  12  07  3f  10  11  01  02  00  01
第四行80  06  00  02  00  00  09  00主機發給設備請求:
按上面的解釋,說明這是主機要求設備上傳配置描述符(02H),因為主機無法得知配置描述符里的wTotallength多大,所以先發個標准長度0009H來試探。
於是設備上傳了09H長的配置描述符:09  02  3b  00  02  01  00  a0  32
主機得知配置總的含有003bH個字節,於是再次發給設備上傳配置描述符的請求:80  06 00 02 00 00 3b  00,要求的總字節長度為003bH
之后設備上傳了003bH的數據:9個配置描述符+9個接口0描述符+9個HID描述符+7個端點1描述符+9個接口1描述符+9個HID描述符+7個端點1描述符
后主機進行設置配置:00  09  01  00  00  00  00  00 設置了配置描述符,使能端點1和端點2

 

USB學習之描述符篇--枚舉 - lastnight1034 - lastnight1034的博客
因為有2個接口,所以分2次分別設置:
EP1:讀取設備描述符,試探性配置描述符,返回鍵盤的配置描述符長度0022H,再次以0022H長度讀取配置描述符。設置配置描述符,掛起等配置完成。
配置完成后讀取HID報告:81  06  00  22  00  00  b5  00
81代表主機發給設備的接口   06代表Get Descriptor   22H為HID報告  wIndex:00為接口0  長度為75H+40H=b5H(?)
設備上傳接口0的0075H長度字節HID報告。
開始設置接口1,仍然繼續讀取設備描述符試探性配置描述符,返回鍵盤的配置描述符長度0022H,再次以0022H長度讀取配置描述符。設置配置描述符,掛起等配置完成。
配置完成后讀取HID報告:不同的是wIndex:0001H 配置接口1,長度為34H+40H=74H(?)
設備上傳接口1的0034H長度字節HID報告。結束后SET REPORT,結束,等待設備上傳端點鍵盤鼠標數據。
 

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:

  • input item tag:指的是從設備的一個或多個類似控制管道得到的數據
  • output item tag:指的是發送給一個或多個類似控制管道的數據
  • feature item tag:表示設備的輸入輸出不面向最終用戶
  • collection item tag:一個有意義的input,output和feature的組合項目
  • end collection item tag:指定一個collectionitem的終止

每一個main item tag(input,output,feature)都表明了來自一個特定管道的數據的大小,數據相對還是獨立,以及其他相關信息。在此之前,global和local item定義了數據的最大值和最小值,等等。local item僅僅描述下一個main item定義的數據域,而global item是這一個報告描述符中所有后續數據段的默認屬性。

 一個報告描述符可能包含多個main item,為了准確描述來自一個控制管道的數據,一個報告描述符必須包括以下內容:

  • input(output,feature)
  • usage
  • usage page
  • Logical Minimum
  • Logical Maximum
  • Report Size
  • Report Count

下面用一個三鍵鼠標舉例說明:

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設備。

 

表1、USB HID規范定義的HID設備可用端點

管道

要求

說明

控制(端點0)

必須

傳輸USB描述符、類請求代碼以及供查詢的消息數據等

中斷輸入

必須

傳輸從設備到主機的輸入數據

中斷輸出

可選

傳輸從主機到設備的輸出數據

 

 

HID設備6種特定請求

 

HID類請求(命令)包格式

偏移量

大小

說明

0

bmRequestType

1

HID設備類請求特性如下:
位7:
0=從USB HOST到USB設備
1=從USB設備到USB HOST
位6~5:
01=請求類型為設備類請求
位4~0:
0001=請求對象為接口(interface)

因而,針對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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM