USB主机是如何检测到设备的插入的呢?
USB設備的插入檢測機制
? ? ??首先,在USB集線器的每個下游端口的D+和D-上,分別接了一個15K歐姆的下拉電阻到地。這樣,在集線器的端口懸空時,就被這兩個下拉電阻拉到了低電平。而在USB設備端,在D+或者D-上接了1.5K歐姆上拉電阻.對于全速和高速設備,上拉電阻是接在D+上;而低速設備則是上拉電阻接在D-上。這樣,當設備插入到集線器時,由1.5K的上拉電阻和15K的下拉電阻分壓,結果就將差分數據線中的一條拉高了。集線器檢測到這個狀態后,它就報告給USB主控制器(或者通過它上一層的集線器報告給USB主控制器),這樣就檢測到設備的插入了。USB高速設備先是被識別為全速設備,然后通過HOST和DEVICE兩者之間的確認,再切換到高速模式的。在高速模式下,是電流傳輸模式,這時將D+上的上拉電阻斷開。??
? ? ?一個簡單的實驗:只用一個上拉電阻接在USB的+5V和D+或者D-上,WINDOWS也會提示發現新硬件,但是無法找到驅動程序。這時去設備管理器里面看,有顯示未知USB設備,并且其VID和PID為0。根據這個,我們可以簡單的判斷設備是否枚舉成功。如下圖所示,分別是枚舉不成功和枚舉成功的圖。
USB設備的枚舉過程:
? ? ?USB主機在檢測到USB設備插入后,就要對設備進行枚舉了。為什么要枚舉呢?枚舉就是從設備讀取一些信息,知道設備是什么樣的設備,如何進行通信,這樣主機就可以根據這些信息來加載合適的驅動程序。調試USB設備,很重要的一點就是USB的枚舉過程,只要枚舉成功了,那么就已經成功大半了。
? ? ? ?在說枚舉之前,先大概說一下USB的一種傳輸模式——控制傳輸。這種傳輸在USB中是非常重要的,它要保證數據的正確性,在設備的枚舉過程中都是使用控制傳輸。控制傳輸分為三個過程:①建立過程。②可選的數據過程。③狀態過程。建立(Setup)過程都是由USB主機發起,它開始于一個Setup令牌包,后面緊跟一個DATA0包。如果是控制輸入傳輸,那么數據過程就是輸入數據;如果是控制輸出傳輸,那么數據過程是輸出數據。如果在設置過程中,指定了數據長度為0,則沒有數據過程。數據過程之后是狀態過程。狀態過程剛好與數據過程的數據傳輸方向相反:如果是控制輸入傳輸,則狀態過程是一個輸出數據包;如果是控制輸出傳輸,則狀態過程是一個輸入數據包。狀態階段用來確認所有的數據都已經正確傳輸。
?枚舉的詳細過程。
? ? ? ?首先,USB主機檢測到USB設備插入后,就會先對設備復位。設備復位后,USB主機就會對地址為0的設備發送獲取設備描述符的標準請求。所有的USB設備在總線復位后其地址都為0,這樣主機就可以跟那些剛剛插入的設備通過地址0通信。主機在建立階段發出獲取設備描述符的輸入請求,設備收到該請求后,在數據過程將設備描述符返回給主機。主機在成功獲取到一個數據包的設備描述符后并且確認沒有什么錯誤后(注意:有些USB設備的端點0大小不足18字節(但至少具有8字節),而標準的設備描述有18字節,在這種情況下,USB設備只能暫時按最大包將部分設備描述符返回,而主機在成功獲取到前面一部分描述符后,就不會再請求剩下的設備描述符部分,而是進入設置地址階段),就會返回一個0長度的狀態數據包給設備。
? ? ? ?然后主機再對設備復位一下,接下來就會進入到設置地址階段。這時USB主機發出一個設置地址的請求(建立過程,設置地址無數據過程),地址包含在建立包中,具體的地址USB主機會負責管理,它會分配一個唯一的地址給新的設備。USB設備在收到地址后,返回0長度的狀態包,主機收到0長度的狀態包之后,會返回一個ACK給設備。設備在收到這個ACK之后,就可以啟用新的地址了。這樣設備就分配到了一個唯一的設備地址,以后主機就通過它來進行訪問該設備。然后主機再次獲取設備描述符,這次跟第一次可能有點不一樣,這次需要獲取完全部的18個字節的設備描述符。當然,如果你的端點0緩沖大于18字節的話,那就跟第一次的情形一樣了。
? ? ?接下來,主機就會獲取配置描述符。配置描述符總共為9字節。主機在獲取到配置描述符后,根據里面的配置集合總長度,再獲取配置集合。配置集合包括配置描述符,接口描述符,端點描符等等。如果有字符串描述符的話,還要獲取字符串描述符。另外HID設備還有HID描述符等。使用BUSHOUND以及通過串口返回信息,很容易看到具體的過程。總之是主機請求什么,你的程序就響應什么.
? ? ? ??USB是個通用的總線,端口都是統一的。但是USB設備卻各種各樣,例如USB鼠標,USB鍵盤,U盤等等,那么USB主機是如何識別出不同的設備的呢?這就要依賴于描述符了。USB的描述符主要有設備描述符,配置描述符,接口描述符,端點描述符,字符串描述符,HID描述符,報告描述符等等.
? ? ?一個USB設備有一個設備描述符,設備描述符里面決定了該設備有多少種配置,每種配置描述符對應著配置描述符;而在配置描述符中又定義了該配置里面有多少個接口,每個接口有對應的接口描述符;在接口描述符里面又定義了該接口有多少個端點,每個端點對應一個端點描述符;端點描述符定義了端點的大小,類型等等。由此我們可以看出,USB的描述符之間的關系是一層一層的,最上一層是設備描述符,下面是配置描述符,再下面是接口描述符,再下面是端點描述符。在獲取描述符時,先獲取設備描述符,然后再獲取配置描述符,根據配置描述符中的配置集合長度,一次將配置描述符、接口描述符、端點描述符一起一次讀回。其中可能還會有獲取設備序列號,廠商字符串,產品字符串等。每種描述符都有自己獨立的編號,如下:
#defineDEVICE_DESCRIPTOR 0x01 //設備描述符
#defineCONFIGURATION_DESCRIPTOR 0x02 //配置描述符
#defineSTRING_DESCRIPTOR 0x03 //字符串描述符
#defineINTERFACE_DESCRIPTOR 0x04 //接口描述符
#defineENDPOINT_DESCRIPTOR 0x05 //端點描述符
?
下面分別詳細介紹一下各描述符。
1.設備描述符
//定義標準的設備描述符結構
typedefstruct_DEVICE_DCESCRIPTOR_STRUCT
{
BYTEblength; //設備描述符的字節數大小
BYTEbDescriptorType; //設備描述符類型編號
WORDbcdUSB; //USB版本號
BYTEbDeviceClass; //USB分配的設備類代碼
BYTEbDeviceSubClass; //USB分配的子類代碼
BYTEbDeviceProtocol; //USB分配的設備協議代碼
BYTEbMaxPacketSize0; //端點0的最大包大小
WORDidVendor; //廠商編號
WORDidProduct; //產品編號
WORDbcdDevice; //設備出廠編號
BYTEiManufacturer; //設備廠商字符串的索引
BYTEiProduct; //描述產品字符串的索引
BYTEiSerialNumber; //描述設備序列號字符串的索引
BYTEbNumConfigurations; //可能的配置數量
}
DEVICE_DESCRIPTOR_STRUCT,*pDEVICE_DESCRIPTOR_STRUCT;
//實際的設備描述符示例
codeDEVICE_DESCRIPTOR_STRUCTdevice_descriptor= //設備描述符
{
sizeof(DEVICE_DESCRIPTOR_STRUCT), //設備描述符的字節數大小,這里是18字節
DEVICE_DESCRIPTOR, //設備描述符類型編號,設備描述符是01
0x1001, //USB版本號,這里是USB01.10,即USB1.1。由于51是大端模式,所以高低字節交換
0x00, //USB分配的設備類代碼,0表示類型在接口描述符中定義
0x00, //USB分配的子類代碼,上面一項為0時,本項也要設置為0
0x00, //USB分配的設備協議代碼,上面一項為0時,本項也要設置為0
0x10, //端點0的最大包大小,這里為16字節
0x7104, //廠商編號,這個是需要跟USB組織申請的ID號,表示廠商代號。
0xf0ff, //該產品的編號,跟廠商編號一起配合使用,讓主機注冊該設備并加載相應的驅動程序
0x0100, //設備出廠編號
?
0x01, //設備廠商字符串的索引,在獲取字符串描述符時,使用該索引號來識別不同的字符串
0x02, //描述產品字符串的索引,同上
0x03, //描述設備序列號字符串的索引,同上
0x01 //可能的配置數為1,即該設備只有一個配置
};
2.配置描述符
//定義標準的配置描述符結構
typedefstruct_CONFIGURATION_DESCRIPTOR_STRUCT
{
BYTEbLength; //配置描述符的字節數大小
BYTEbDescriptorType; //配置描述符類型編號
WORDwTotalLength; //此配置返回的所有數據大小
BYTEbNumInterfaces; //此配置所支持的接口數量
BYTEbConfigurationValue; //Set_Configuration命令所需要的參數值
BYTEiConfiguration; //描述該配置的字符串的索引值
BYTEbmAttributes; //供電模式的選擇
BYTEMaxPower; //設備從總線提取的最大電流
}
CONFIGURATION_DESCRIPTOR_STRUCT,*pCONFIGURATION_DESCRIPTOR_STRUCT;
3.接口描述符
//定義標準的接口描述符結構
typedefstruct_INTERFACE_DESCRIPTOR_STRUCT
{
BYTEbLength; //接口描述符的字節數大小
BYTEbDescriptorType; //接口描述符的類型編號
BYTEbInterfaceNumber; //該接口的編號
BYTEbAlternateSetting; //備用的接口描述符編號
BYTEbNumEndpoints; //該接口使用的端點數,不包括端點0
BYTEbInterfaceClass; //接口類型
BYTEbInterfaceSubClass; //接口子類型
BYTEbInterfaceProtocol; //接口遵循的協議
BYTEiInterface; //描述該接口的字符串索引值
}
INTERFACE_DESCRIPTOR_STRUCT,*pINTERFACE_DESCRIPTOR_STRUCT;
4.端點描述符
//定義標準的端點描述符結構
typedefstruct_ENDPOINT_DESCRIPTOR_STRUCT
{
BYTEbLegth; //端點描述符字節數大小
BYTEbDescriptorType; //端點描述符類型編號
BYTEbEndpointAddress; //端點地址及輸入輸出屬性
BYTEbmAttributes; //端點的傳輸類型屬性
WORDwMaxPacketSize; //端點收、發的最大包大小
BYTEbInterval; //主機查詢端點的時間間隔
}
ENDPOINT_DESCRIPTOR_STRUCT,*pENDPOINT_DESCRIPTOR_STRUCT;
下面是一個配置描述符集合的定義
typedefstruct_CON_INT_ENDP_DESCRIPTOR_STRUCT
{
CONFIGURATION_DESCRIPTOR_STRUCTconfiguration_descriptor;
INTERFACE_DESCRIPTOR_STRUCT interface_descritor;
ENDPOINT_DESCRIPTOR_STRUCT endpoint_descriptor[ENDPOINT_NUMBER];
}CON_INT_ENDP_DESCRIPTOR_STRUCT;
配置描述符集合的示例
codeCON_INT_ENDP_DESCRIPTOR_STRUCTcon_int_endp_descriptor= //配置描述符集合
{
//configuration_descriptor //配置描述符
{
sizeof(CONFIGURATION_DESCRIPTOR_STRUCT), //配置描述符的字節數大小,這里為9
CONFIGURATION_DESCRIPTOR, //配置描述符類型編號,配置描述符為2
(sizeof(CONFIGURATION_DESCRIPTOR_STRUCT)+
sizeof(INTERFACE_DESCRIPTOR_STRUCT)+
sizeof(ENDPOINT_DESCRIPTOR_STRUCT)*ENDPOINT_NUMBER)*256+
(sizeof(CONFIGURATION_DESCRIPTOR_STRUCT)+
sizeof(INTERFACE_DESCRIPTOR_STRUCT)+
sizeof(ENDPOINT_DESCRIPTOR_STRUCT)*ENDPOINT_NUMBER)/256, //配置描述符集合的總大小
0x01, //只包含一個接口
0x01, //該配置的編號
0x00, //iConfiguration字段
0x80, //采用總線供電,不支持遠程喚醒
0xC8 //從總線獲取最大電流400mA
},
//interface_descritor //接口描述符
{
sizeof(INTERFACE_DESCRIPTOR_STRUCT), //接口描述符的字節數大小,這里為9
INTERFACE_DESCRIPTOR, //接口描述符類型編號,接口描述符為3
0x00, //接口編號為4
0x00, //該接口描述符的編號為0
ENDPOINT_NUMBER, //非0端點數量為2,只使用端點主端點輸入和輸出
0x08, //定義為USB大容量存儲設備
0x06, //使用的子類,為簡化塊命令
0x50, //使用的協議,這里使用單批量傳輸協議
0x00 //接口描述符字符串索引,為0,表示沒有字符串
},
//endpoint_descriptor[]
{
{ //主端點輸入描述
sizeof(ENDPOINT_DESCRIPTOR_STRUCT), //端點描述符的字節數大小,這里為7
ENDPOINT_DESCRIPTOR, //端點描述符類型編號,端點描述符為5
MAIN_POINT_IN, //端點號,主輸入端點
ENDPOINT_TYPE_BULK, //使用的傳輸類型,批量傳輸
0x4000, //該端點支持的最大包尺寸,64字節
0x00 //中斷掃描時間,對批量傳輸無效
},
{ //主端點輸出描述
sizeof(ENDPOINT_DESCRIPTOR_STRUCT), //端點描述符的字節數大小,這里為7
ENDPOINT_DESCRIPTOR, //端點描述符類型編號,端點描述符為5
MAIN_POINT_OUT, //端點號,主輸出端點
ENDPOINT_TYPE_BULK, //使用的傳輸類型,批量傳輸
0x4000, //該端點支持的最大包尺寸,64字節
0x00 //中斷掃描時間,對批量傳輸無效
}
其中關于端點的類型定義如下
//定義的端點類型
#defineENDPOINT_TYPE_CONTROL 0x00 //控制傳輸
#defineENDPOINT_TYPE_ISOCHRONOUS 0x01 //同步傳輸
#defineENDPOINT_TYPE_BULK 0x02 //批量傳輸
#defineENDPOINT_TYPE_INTERRUPT 0x03 //中斷傳輸
端點號的定義如下
#defineMAIN_POINT_OUT 0x02 //2號輸出端點
#defineMAIN_POINT_IN 0x82 //2號輸入端點
?
?
?
總結
以上是生活随笔為你收集整理的USB主机是如何检测到设备的插入的呢?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 文件夹没有安全选项-文件上传下载-路径访
- 下一篇: 安装 Tableau Desktop 时