USB開裝置開發學習之二: USB具體通訊過程(含列舉過程)
原文:https://blog.csdn.net/go_str/article/details/80802452
前言
現在剛開始接觸USB的開發,零零散散學習了一些USB基礎知識,但是卻得不到連貫。在這個學習過程中首先困惑的就是USB通訊過程究竟是什麼樣子的,我覺得做一下的瞭解後整合後記錄下來,首先從USB整體結構基礎來入手直到整個通訊過程。可能有理解不到位的地方,望各位能夠指正,我會及時改正。
一、USB系統的結構
USB系統是由三個邏輯層組成:功能層、USB裝置層和USB匯流排介面層。並且每一層都是由主機和USB裝置不同的功能模組組成,如下圖所示:
1、功能層(介面)
功能層是由客戶軟體和裝置方的功能單元組成,其能夠實現USB裝置傳輸的特定功能。通過功能層可直觀地理解USB傳輸的資料內容。其中,客戶軟體通過USB系統軟體來與USB裝置進行通訊。功能單元對於客戶軟體,可視為介面的集合。
2、USB裝置層 (端點)
USB裝置層是由USB系統軟體和USB裝置的USB邏輯裝置組成,其實現主機和USB裝置之間傳輸的具體配置。USB邏輯裝置對於USB系統軟體,可視為端點的集合。
3、USB匯流排介面層
USB匯流排介面層是由主機的USB主控制器和裝置的USB匯流排介面組成。其實現主機和USB裝置實際的資料傳輸。
4、主機部分
USB主機部分由客戶軟體、USB系統軟體和USB匯流排介面組成。
4.1 客戶軟體
客戶軟體負責和USB裝置的功能單元進行通訊,以實現特定的功能。客戶軟體不能直接與USB裝置相連線,必須通過USB系統軟體和USB匯流排接口才能實現連線。客戶軟體包括USB裝置驅動程式和介面應用程式兩部分。
4.2 USB系統軟體
USB系統軟體負責和USB邏輯裝置進行配置通訊,並管理客戶軟體啟動的資料。一般包括USB匯流排驅動程式、USB主控制驅動程式和非USB主機軟體三個部分,這部分會由系統提供。
4.3 USB匯流排接
USB匯流排介面包括主控制器和跟集線器兩部分。其中,主控制器是負責完成主機和USB裝置間的資料實際傳輸。根集線器是為USB系統連線起點。
5、裝置部分
USB裝置部分由三個功能模組組成,分別是USB匯流排介面、USB邏輯裝置和功能單元。
功能單元看作是一個介面的集合;USB 邏輯裝置被USB系統軟體看作一個端點的集合;USB匯流排介面是USB裝置中的序列介面引擎(SIE)。
當客戶程式通過USB管道傳送或接收資料時,它首先呼叫Win32 APl,呼叫最終將使功能驅動程式收到一個IRP。而驅動程式的工作就是把客戶的請求引導到有正確端點的管道上。它把請求提交到匯流排驅動程式,匯流排驅動程式再把請求分解成多個事務,然後這些事務被送往匯流排。總線上的資訊流以每毫秒一幀資料的形式流動。匯流排驅動程式必須安排好多個事務以使它們能被裝入同一幀中。
二、USB的拓撲結構
USB是一種主從結構的系統。主機叫Host,從機叫做Device(也叫裝置)。通常所說的主機具有一個或者多個USB主控制器(host controller)和根集線器(root hub)。主控制器主要負責資料處理,而跟集線器則提供一個連線主控制器與裝置之間的介面和通路。
通常情況下,PC機上有多個主控器和多個USB口,一個主控器下有一根集線器,一根集線器通常具有一個或者幾個USB介面。通常集線器可以通過USB集線器來擴充套件USB介面,只是頻寬是不能夠拓寬的,因為頻寬是共享一個USB主控器的。
瞭解上面的資訊後,再來看USB的拓撲結構如下圖:
USB的拓撲結構看起來是一個金字塔形的結構,具體構成如下:
塔頂是USB的主控器和根集線器,下面接USB集線器,USB集線器將一個USB口擴充套件為多個USB口,多個USB口同樣可以通過USB集線器擴展出更多的介面。不過USB口並不能通過USB集線器無止境的擴充套件,他是有限制的,例如在USB2.0規定它最多擴充套件6次。
理論上一個USB主控器最多可接127個裝置,這是因為協議規定每個USB裝置具有一個7bit地址(取值範圍為0~127,地址用於給主機識別是哪個裝置,其中0地址值得注意,是給剛接入未初始化的裝置使用的)。
三、USB的裝置架構
裝置架構認為裝置是由一些配置、介面和端點構成的。其中配置和介面是USB功能的抽象,實際的資料傳輸由端點來完成。其對應關係如下圖所示:
1.裝置
裝置代表USB裝置,它由一個或多個配置組成。裝置描述符用於說明裝置的總體資訊,並指出其所包含配置的個數。
2.配置
在使用USB裝置前,必須為其選擇一個合適的配置。如USB裝置的低功耗模式和高功耗模式分別對應一個配置。配置描述符用於說明USB裝置中各個配置的特性。
3.介面
一個配置可以包含一個或多個介面。介面是一個端點的集合。介面描述符用於說明USB裝置中各個介面的特性。
4.端點
端點是USB裝置中的實際物理單元,USB資料傳輸就是在主機和USB裝置各個端點之間進行的。
5、管道
管道,是主機軟體(資料緩衝區)和USB裝置的各個端點之間的資料傳輸連結,它是兩者之間通訊流的抽象。然而,實際的資料傳輸是由USB匯流排介面層來完成的。管道和USB裝置中的端點一一對應,並且各個管道的資料傳輸是相互獨立的。
管道有兩種型別:流管道和訊息管道。其中最為重要的訊息管道是“預設控制管道”,這個管道在裝置開始上電後就存在了,它用於提供裝置的配置與狀態等資訊。主機與裝置之間的聯絡就是通過訊息管道實現的。
四、USB列舉與通訊的具體過程
1、USB接頭
下圖是一個USB接頭的結構圖:
由圖可以看出,標準的USB連結線使用4芯電纜:5V電源線(Vbus)\差分資料線負(D-)、差分資料線正(D+)和地線(GND)。
在hub端,資料線D+和D-都有一個阻值在14.25k到24.8k的下拉電阻Rpd,而在裝置端,D+(全速,高速)和D-(低速)上有一個1.5k的上拉電阻Rpu。當裝置插入到hub埠時,有上拉電阻的一根資料線被拉高到幅值的90%的電壓(大致是3V)。hub檢測到它的一根資料線是高電平,就認為是有裝置插入,並能根據是D+還是D-被拉高來判斷到底是什麼裝置(全速/低速)插入埠。
2、USB通訊過程
主機和USB裝置可以相互傳輸資料,其具體過程如下(以主機箱裝置傳輸為例):
step1:客戶軟體首先將要傳輸的資料放入緩衝區,同時向USB匯流排驅動程式發出IRPS,請求資料傳輸。(客戶軟體)step2:USB匯流排驅動接收到程式接收請求,並對資料進行處理,轉化為具有USB格式的事務處理。(USB系統軟體)
step3:USB主控制器驅動程式將這些事務處理建立成事務列表,同時要求不能超過USB頻寬。(USB系統軟體)
step4:USB主控制器讀取到事務列表並將事務轉化為資訊包,傳送到USB總線上。(USB匯流排介面)
step5:USB裝置收到這些資訊後,SIE(USB匯流排介面是USB裝置中的序列介面引擎)將其解包後放入指定端點的接收緩衝區內,由晶片韌體對其進行處理。
用框圖表示如下:
3、USB列舉通訊具體過程
列舉就是從裝置讀取一些資訊,知道裝置是什麼樣的裝置,如何進行通訊,這樣主機就可以根據這些資訊來載入合適的驅動程式。除錯USB裝置,很重要的一點就是USB的列舉過程,只要列舉成功了,那麼就已經成功大半了。
列舉通訊過程具體如下:
step1:檢測電壓變化,報告主機
首先,USB裝置上電後,一直監測USB裝置介面電平變化HUB檢測到有電壓變化,將利用自己的中斷端點將資訊反饋給主控制器有裝置連線。
Step2:主機瞭解連線裝置
主機在知道有裝置接入後會傳送一個Get_Port_Status請求(request)給hub以瞭解此次狀態改變的確切含義。
Step3:Hub檢測所插入的裝置是高速還是低速
hub通過檢測USB匯流排空閒(Idle)時差分線的高低電壓來判斷所連線裝置的速度型別,當host發來Get_Port_Status請求時,hub就可以將此裝置的速度型別資訊回覆給host。USB 2.0規範要求速度檢測要先於復位(Reset)操作。
Step4:hub復位裝置
主機一旦得知新裝置已連上以後,它至少等待100ms以使得插入操作的完成以及裝置電源穩定工作。然後主機控制器就向hub發出一個 Set_Port_Feature請求讓hub復位其管理的埠(剛才裝置插上的埠)。hub通過驅動資料線到復位狀態(D+和D-全為低電平 ),並持續至少10ms。當然,hub不會把這樣的復位訊號傳送給其他已有裝置連線的埠,所以其他連在該hub上的裝置自然看不到復位訊號,不受影響。
Step5: Host檢測所連線的全速裝置是否是支援高速模式
因為根據USB 2.0協議,高速(High Speed)裝置在初始時是預設全速(Full Speed )狀態執行,所以對於一個支援USB 2.0的高速hub,當它發現它的埠連線的是一個全速裝置時,會進行高速檢測,看看目前這個裝置是否還支援高速傳輸,如果是,那就切到高速訊號模式,否則就一直在全速狀態下工作。
同樣的,從裝置的角度來看,如果是一個高速裝置,在剛連線bub或上電時只能用全速訊號模式執行(根據USB 2.0協議,高速裝置必須向下相容USB 1.1的全速模式)。隨後hub會進行高速檢測,之後這個裝置才會切換到高速模式下工作。假如所連線的hub不支援USB 2.0,即不是高速hub,不能進行高速檢測,裝置將一直以全速工作。
Step6:Hub建立裝置和主機之間的資訊通道
主機不停地向hub傳送Get_Port_Status請求,以查詢裝置是否復位成功。Hub返回的報告資訊中有專門的一位用來標誌裝置的復位狀態。
當hub撤銷了復位訊號,裝置就處於預設/空閒狀態(Default state),準備接收主機發來的請求。裝置和主機之間的通訊通過控制傳輸,預設地址0,端點號0進行。此時,裝置能從總線上得到的最大電流是100mA。(所有的USB裝置在匯流排復位後其地址都為0,這樣主機就可以跟那些剛剛插入的裝置通過地址0通訊。)
Step7:主機發送Get_Descriptor請求獲取預設管道的最大包長度
預設管道(Default Pipe)在裝置一端來看就是端點0。主機此時傳送的請求是預設地址0,端點0,雖然所有未分配地址的裝置都是通過地址0來獲取主機發來的請求,但由於列舉過程不是多個裝置並行處理,而是一次列舉一個裝置的方式進行,所以不會發生多個裝置同時響應主機發來的請求。
裝置描述符的第8位元組代表裝置端點0的最大包大小。雖然說裝置所返回的裝置描述符(Device Descriptor)長度只有18位元組,但系統也不在乎,此時,描述符的長度資訊對它來說是最重要的,其他的瞄一眼就過了。當完成第一次的控制傳輸後,也就是完成控制傳輸的狀態階段,系統會要求hub對裝置進行再一次的復位操作(USB規範裡面可沒這要求)。再次復位的目的是使裝置進入一個確定的狀態。
Step8:主機給裝置分配一個地址
主機控制器通過Set_Address請求向裝置分配一個唯一的地址。在完成這次傳輸之後,裝置進入地址狀態(Address state),之後就啟用新地址繼續與主機通訊。這個地址對於裝置來說是終生制的,裝置在,地址在;裝置消失(被拔出,復位,系統重啟),地址被收回。同一個裝置當再次被列舉後得到的地址不一定是上次那個了。
Step9:主機獲取裝置的資訊
主機發送 Get_Descriptor請求到新地址讀取裝置描述符,這次主機發送Get_Descriptor請求可算是誠心,它會認真解析裝置描述符的內容。裝置描述符內資訊包括端點0的最大包長度,裝置所支援的配置(Configuration)個數,裝置型別,VID(Vendor ID,由USB-IF分配), PID(Product ID,由廠商自己定製)等資訊。
之後主機發送Get_Descriptor請求,讀取配置描述符(Configuration Descriptor),字串等,逐一瞭解裝置更詳細的資訊。事實上,對於配置描述符的標準請求中,有時wLength一項會大於實際配置描述符的長度(9位元組),比如255。這樣的效果便是:主機發送了一個Get_Descriptor_Configuration 的請求,裝置會把介面描述符,端點描述符等後續描述符一併回給主機,主機則根據描述符頭部的標誌判斷送上來的具體是何種描述符。
接下來,主機就會獲取配置描述符。配置描述符總共為9位元組。主機在獲取到配置描述符後,根據裡面的配置集合總長度,再獲取配置集合。配置集合包括配置描述符,介面描述符,端點描符等等。
如果有字串描述符的話,還要獲取字串描述符。另外HID裝置還有HID描述符等。
Step10: 主機給裝置掛載驅動(複合裝置除外)
主機通過解析描述符後對裝置有了足夠的瞭解,會選擇一個最合適的驅動給裝置。 然後tell the world(announce_device)說明裝置已經找到了,最後呼叫裝置模型提供的介面device_add將裝置新增到 usb 匯流排的裝置列表裡,然後 usb匯流排會遍歷驅動列表裡的每個驅動,呼叫自己的 match(usb_device_match) 函式看它們和你的裝置或介面是否匹配,匹配的話呼叫device_bind_driver函式,現在就將控制權交到裝置驅動了。
對於複合裝置,通常應該是不同的介面(Interface)配置給不同的驅動,因此,需要等到當裝置被配置並把介面使能後才可以把驅動掛載上去。
Step11:裝置驅動選擇一個配置
驅動(注意,這裡是驅動,之後的事情都是有驅動來接管負責與裝置的通訊)根據前面裝置回覆的資訊,傳送Set_Configuration請求來正式確定選擇裝置的哪個配置(Configuration)作為工作配置(對於大多數裝置來說,一般只有一個配置被定義)。至此,裝置處於配置狀態(Configured),當然,裝置也應該使能它的各個介面(Interface)。
對於複合裝置,主機會在這個時候根據裝置介面資訊,給它們掛載驅動