usb協議分析-設備描述符配置包-描述符


/* usb協議分析僅供大家參考---設備描述符配置包,設備描述符, 地址設置, 配置描述符, 字符串描述符 */

/*
-1- usb設備描述符配置包 */ typedef struct _USB_SETUP_PACKET { REQUEST_TYPE bmRequestType; BYTE bRequest; WORD_BYTE wValue; WORD_BYTE wIndex; WORD wLength; } USB_SETUP_PACKET; 1.bmRequestType 是包含有下面幾方面的內容: D7 D6 D5 D4 D3 D2 D1 D0 在這一個字節里,又按位分為: D7位是表示后面傳送數據的方向位。 當D7等於0時,表示后面的數據是從主控器發送到USB設備。在PC里,就是從PC機發送到USB的設備。 當D7等於1時,表示后面的數據是從USB設備發送到主控器。在PC里,就是從USB設備發送到USB設備。 在上次里,我收到並顯示出來的數據是80,就表示從USB設備里發送數據給PC。在這里再次給出上一次的包數據: 80 06 00 01 00 00 40 00 這里的80,就是D7位為1。 D6-D5位是請求主分類型 0 是表示標准的請求。 1 是表示類別的請求。 2 是表示廠商的請求。 3 是保留。 D4-D0位是表求接收這個包的接口。 0 是表示USB設備接收。 1 是表示接口接收。 2 是表示端點接收。 3 是表示其它接收,不知道的。 4-31是保留。 2.bRequest 是本描述符的請求類型,也就是后面發送的數據是什么樣的東西。 由於USB里有很多配置信息,比如獲取設備描述符,又有設置USB地址等等,就是通過這個字節來區分的。 從USB協議里查找表9-4,就可看到如下的編碼: 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_CONFIGURATION 8 SET_CONFIGURATION 9 GET_INTERFACE 10 SET_INTERFACE 11 SYNCH_FRAME 12 在上面的數據包里,看到它的內容是06,那么它就是GET_DESCRIPTOR類型。也就是主控器想讀取USB設備的描述符, 到這里就已經分析出來的意思,就是主控器想讀取USB描述符,但還不知道是什么描述符的內容。 3.wValue是根據不同的請求而設置不同的值。一般就是傳送參數給設備標明這是什么請求。在上面GET_DESCRIPTOR獲取設備描述符里,它的值是00 01。 在GET_DESCRIPTOR里這個字段的低字節表示描述符的索引,高字節表示描述符的類型。高字節的類型如下: DEVICE 1 CONFIGURATION 2 STRING 3 INTERFACE 4 ENDPOINT 5 DEVICE_QUALIFIER 6 OTHER_SPEED_CONFIGURATION 7 INTERFACE_POWER1 8 wValue值在這里的高字節是01,那么它就是設備描述符了。低字節是00,那么它就是表示從偏移地址0開始讀取設備描述符。 由於在配置描述符里有很多配置,所以低字節在那里就可以用來識別獲取同樣類型的描述符不同的配置。 4.wIndex是根據不同的請求而設置不同的值。一般用來說明端點號或者說明接口標識。在獲取描述符里,設置為0,或者是語言ID。 在這個發送的描述符里,它是設置為00 005.wLength是根據請求來決定下一階段發送數據的長度。前面請求第一個字節里,已經說明下一階段數據傳送的方向, 這里說明了傳送數據的長度。不管是發送數據,還是接收數據,都不要超過這個數據長度,否則主機會出問題,或者設備有問題。 在這個獲取設備描述里,它的長度是40 00,按小端格式去解釋,就是64個字節。 到這里,就把主控器發下來的數據解釋完成了,知道去做什么的事情和回應。下一次就去分析怎么樣返回設備描述符。 /* ------------------------------------------------------------------------------------------------ */ /* -2- 回應設備描述符 */ 上一次已經介紹怎么樣收到主控器的獲取設備描述符的數據,這里就解釋怎么樣發送回應數據給主控器。 先從USB協議里找到標准設備的定義,我把它用C語言定義如下: typedef struct _USB_DEVICE_DESCRIPTOR { BYTE bLength; BYTE bDescriptorType; WORD bcdUSB; BYTE bDeviceClass; BYTE bDeviceSubClass; BYTE bDeviceProtocol; BYTE bMaxPacketSize0; WORD idVendor; WORD idProduct; WORD bcdDevice; BYTE iManufacturer; BYTE iProduct; BYTE iSerialNumber; BYTE bNumConfigurations; } USB_DEVICE_DESCRIPTOR; 返回給主控器的數據結構就是上面的內容,只要把上面的結構填寫合適的內容,就可以發送回去給主控器。 在我的USB設備里,我把它填寫如下的數據: 12 01 10 01 00 00 00 40 00 80 00 80 00 01 04 2C 4A 01 看到這串數據是不明白是什么東西的,現在就來仔細地分析它的具體定義。下面就按着一個字段一個字段地分析它。 bLength是本結構的數據長度,這樣可以方便以后兼容不同的版本協議。因為不同的結構是不同的長度,這樣就可以區分不同的協議了。 比如有一天想添加一個字段,那么它的長度就會改變,這時就可以根據不同的長度進行解釋不同的協議了。 這次返回的結構長度是0x12,也就是18個字節,它的長度是從bLength長度開始,也就是說是完全整個結構的長度。 bDescriptorType是描述符的類型。它的定義跟主控器發下來描述符的類型是一樣的,如下: DEVICE 1 CONFIGURATION 2 STRING 3 INTERFACE 4 ENDPOINT 5 DEVICE_QUALIFIER 6 OTHER_SPEED_CONFIGURATION 7 INTERFACE_POWER1 8 由於返回的是設備描述符,所以就選擇了1,也就是包里顯示的第二個字節01。用這個類型來區分不同的描述符。 bcdUSB是USB發布的協議版本。也就是本設備能適用於那種協議,目前USB主要有兩個版本,一個是1.10,一個是2.10版本。 在本設備里,采用了1.10的協議版本。由於這個字段是采用BCD編碼,所以1.10的表示為0x0110的格式,按小端格式輸出來,就變成10 01的顯示了。 bDeviceClass是設備分類。當它的值是0時,表示所有接口在配置描述符里,並且所有接口是獨立的。 當它的值是1到FEH時,表示不同的接口關聯的。當它的值是FFH時,它是廠商自己定義的。在這個設備里,是定義為0。 bDeviceSubClass是設備子分類碼。當前面的bDeviceClass值是0時,這里一定要設置為0。其它就跟據USB-IF組織定義的編碼。 bDeviceProtocol是設備使用的協議。如果使用USB-IF組織定義的協議,就需要設置這里的值。如果不使用,就直接設置為0。 如果廠商自己定義的可以設置為FFH。 以上三個值,在本設備里全部設置為0。 bMaxPacketSize0是端點0收發最大的包大小。僅允許設置8,1632,64中的任何一個大小。在本設備里是設置為64個字節大小。所以看到這個字段是40 的大小。 12 01 10 01 00 00 00 40 00 80 00 80 00 01 04 2C 4A 01 idVendor是廠商標識。由USB-IF分配的編碼。在這里使用0x8000。 idProduct是廠商定義的產品標識。由廠家和產品標識,就可以讓操作系統加載不同的驅動程序。如下: 12 01 10 01 00 00 00 40 00 80 00 80 00 01 04 2C 4A 01 bcdDevice是用BCD表示的設備發布的版本號。這里是1.0012 01 10 01 00 00 00 40 00 80 00 80 00 01 04 2C 4A 01 iManufacturer是廠商字符串的偏移值。這值主要說明了它在字符串描述符里的偏移位置。如果它設置為0,表示沒有廠商字符串。在 這里是0x04,就是從字符串描述符開始位置算起第4個字節位置讀取字符串。 iProduct是產品字符串的偏移值。這值主要說明了它在字符串描述符里的偏移位置。如果它設置為0,表示沒有產品字符串。 在這里是0x2C,就是從字符串描述符開始位置算起第2C個字節位置讀取字符串。 iSerialNumber是序列號字符串的偏移值。這值主要說明了它在字符串描述符里的偏移位置。如果它設置為0,表示沒有序列號字符串。 在這里是0x4A,就是從字符串描述符開始位置算起第4A個字節位置讀取字符串。 所有字符串,都是采有UNICODE編碼。 bNumConfigurations是配置描述符的個數。在這里只使用了一個配置,所以設置為1。 /* ------------------------------------------------------------------------------------------------ */ /* -3- 設置USB地址 */ 前面已經解釋主控器怎么樣發送設備描述符下來,然后設備返回相應的設備描述符。下一步主控器的動作是做什么呢? 由於在USB總線上的設備有很多,為了區分不同的設備通訊,就需要給每個設備分配一個地址,這跟網絡中的IP地址是一樣的,或者跟MAC地址也是一樣的。 因而,接着下來就是主控器分配地址給設備,USB的設備地址是從1開始到127。下面就是接收到主控器發下來的數據包: 00 05 01 00 00 00 00 00 由USB_SETUP_PACKET定義具體地分析這個數據,就可以知道應做什么樣的響應了。下面就來解釋這個操作。 先取得bmRequestType的類型,也就是第一個字節,它是00。從USB協議里查看,它的方向位是主控器發送給設備, 由D6D5位就知道它是USB協議里定義的標准請求,由D4-D0位知道它是USB設備接收這個包數據。 bRequest是05,從前面已經介紹的類型,就知道它是設置地址,如下: SET_ADDRESS 5 所以這個包需要按設置地址的格式去解釋后面的數據。 由於USB協議可以知道,USB的設備地址放在字段wValue里,因它的值是01 00,按小端格式解釋就是0x0001了。 其它相應的字段wIndex和wLength應都是0,如果是其它非0的數據,是沒有定義的。 USB的串行引擎通過這個地址來判斷是否接收總線上的數據,如果發送的地址跟它一致,就會接收主控器發過來的數據, 當然從這個設備發送出去的數據也帶有這個地址,因此就可以讓主控器識別不同的USB設備數據了。 /* ------------------------------------------------------------------------------------------------ */ /* -4- 配置描述符 */ 前面已經介紹設置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 6 wValue是00 02。低字節表示偏移地址00,高字節表示描述符的類型。如下: CONFIGURATION 2 所以這里的返回的設備描述符是配置描述符。 wIndex是00 00。 wLength是09 00。它表示返回描述符的長度。這里是9個字節。 接着下來,就是設備返回配置描述符給主控器,發送的數據如下: 09 02 22 00 01 01 00 01 32 發送的數據是按下面的結構來定義,這也是在USB協議里定義的格式。如下: typedef struct _USB_CONFIGURATION_DESCRIPTOR { BYTE bLength; BYTE bDescriptorType; WORD wTotalLength; BYTE bNumInterfaces; BYTE bConfigurationValue; BYTE iConfiguration; BYTE bmAttributes; BYTE MaxPower; } USB_CONFIGURATION_DESCRIPTOR; bLength是配置的長度,也就是配置結構的整個長度。在這里9個字節。 bDescriptorType是描述符的類型,這里配置描述符,所以設置為02。 wTotalLength是所有配置設置的結構長度。包括配置描述符、接口描述符、HID或者其它描述符和端點描述符的長度。這里是22 00,也就是0x0022個字節。 bNumInterfaces是接口個數,這里一個。 bConfigurationValue是配置的個數,當設置配置時發送的值。這時設置為1個配置。 iConfiguration是說明配置的字符的偏移值。這里是0。 bmAttributes是配置特性,D7位保留。D6位是說明是否自供電。D5位是否支持遠程喚醒。D4—D0是保留,設置為0。 MaxPower是使用的功率,它采用電流來表示。每2mA為單位,比如它的值是50時就表示是100mA的電流消耗。 通過這樣說明,主控器就知道這個設備是什么樣的設備,有多少功能。 /* ------------------------------------------------------------------------------------------------ */ /* -5- 字符串描述符 */ 上一次說到把配置描述符返回給主控器那里了,現在接着下來,就會收到主控器發來字符串描述符。如果在設備描述符那里指定沒有字符串描述的話, 在這里是不會收到字符串描述符的。由於我在設備描述符里指定有字符串描述符的偏移地址,因此,就收到主控器發出請求字符串描述符。收到的數據如下: 80 06 00 03 00 00 FF 00 bmRequestType是80,表示方向USB設備發送給主控器,接收設備是USB設備。 bRequest是06,表示這是獲取描述符。GET_DESCRIPTOR 6 wValue是00 03。低字節表示偏移地址00,高字節表示描述符的類型,如下: STRING 3 wIndex是00 00。 wLength是FF 00。它表示返回描述符的長度。這里是256個字節。 因此,這個獲取字符串描述符,就是從字符串描述內存里,0偏移地址開始的位置讀取第一個字符串描述符返回給主控器。接着就返回下面的數據給主控器: 04 03 09 04 上面的數據是按字符串描述符來組織的,它的結構,我定義結構如下: typedef struct _USB_STRING_DESCRIPTOR { BYTE bLength; BYTE bDescriptorType; WORD bString/*[]*/; } USB_STRING_DESCRIPTOR; bLength是所有數據的長度。在這里是4。 bDescriptorType是描述類型,這里字符串描述符,所以它是3。 bString是可變的字符數組。不超過254個應都可以的,並且它是使用UNICODE編碼的字符串。 在這里是09 04,這是美國英語的標識,0x0409。如果想輸入中文的標識,只要改為0x0804就可以了。 通過這個字符串描述符,主控器就知道字符串描述符是使用什么語言說明的了,這樣就可以支持全世界的語言標識。

 


免責聲明!

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



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