在上一篇文章中我們知道了usb協議中的域、包、事務、傳輸的基本概念,下面我們來看看usb第一個通信過程—枚舉。
枚舉就是從設備讀取一些信息,知道設備是什么樣的設備,如何進行通信,這樣主機就可以根據這些信息來加載合適的驅動程序。這部分內容同上一篇文章一樣,是一些接近物理層的過程,而且其中大部分細節都由硬件模塊完成,對于linux驅動工程師來說只需要了解,并不用深陷其中無法自拔。(這部分PHY層細節還是留給數字邏輯工程師去研究吧!驅動工程師只需要有這方面概念,出現問題能夠思路全面就可以了)
下圖是一個usb全速設備的枚舉過程抓包,下面具體分析一下:

點擊圖片查看大圖
第一步:區分設備類型
usb設備分為低速設備(1.5Mbps)、全速設備(12Mbps)、高速設備(480Mbps),它們的區分就是在設備上電第一瞬間區分的:
1, 低速設備與全速設備在設備端的區別
設備端一般有900~1575Ω的上拉電阻,全速設備該電阻在D+上,低速設備在D-上。上圖Speed一列中的FS就代表全速設備了,即FullSpeed。
2, 設備是否支持高速模式
因為usb只有兩根數據線,沒有辦法識別出低速、全速之外的高速模式。檢測設備是否支持高速模式是在reset信號后由host發送一串KJKJKJ的序列,如設備支持高速狀態則做出相應的調整,切換到高速模式。最初高速設備同全速設備一樣,D+信號上存在1.5KΩ的上拉電阻,在切換到高速模式后D+的上拉電阻才會斷開(USB設備中的控制器能夠控制信號線上拉電阻的開關)連接D+/D-上的高速終端電阻(high-speed termination)。上圖中Reset信號后的High speed Detection Handshake這就是檢測設備是否支持高速模式的檢測。如果支持高速設備在speed一列中后面的符號會變成HS,即High Speed。(其中KJ信號是指在D+、D-線上出現的約0.8V的中間電平信號,如想更詳細了解這部分的細節可以參考一篇網上的描述http://www.cnblogs.com/AlwaysOnLines/p/3842886.html。)
第二步:獲取設備描述符的前8個字節
usb設備在上電后默認的地址為0,而且usb設備是逐一進行枚舉的,即同一時刻usb總線上也只有一個設備地址為0。host端對0地址設備發出請求來獲取設備描述符的前8個字節。(枚舉過程使用的是控制傳輸,對應的斷點是0)這是要干什么呢?下面是此次獲取的8個字節的抓包圖,其中包括了usb協議版本,圖中為1.1;設備類型,圖中為Hub;設備協議,圖中為None;這些都不重要!之所以只獲取8個字節當然是為了得到第八個字節的數據。圖中綠框已經圈出重點,這代表此設備端點0支持的的最大包大小。只有知道了這個數據才能在之后的數據傳輸中合理的控制包大小,大量傳輸數據,不然使用了設備不支持包大小就會被設備丟棄,發生傳輸錯誤了。

點擊圖片查看大圖
第三步:設置地址
主機通過發送一個Set_Address請求來分配一個唯一的地址給設備。設備讀取這個請求,返回一個確認,并保存新的地址。從此開始所有通信都使用這個新地址。從上圖可以看到host給當前device分配的地址為1,之后的通信地址都有0改為1了。
第四步:獲取所有描述符
確認了地址之后通信就進入正軌了,終于可以肆無忌憚的發送數據了。主機向新地址重新發送Get_Device_Descriptor命令,此次讀取其設備描述符的全部字段,以了解該設備的總體信息,如VID,PID。之后host還會發出Get_Configuration_Description獲取設備的配置描述符;發送Get_Device_String命令,獲得字符集描述(unicode),比如產商、產品描述、型號等等。
自此usb枚舉過程完成了,之后就可以按照不同設備進行相應數據的傳輸。
新聞熱點
疑難解答