由于 USB 只是一個設備接入到系統中的方式,對于大部分用戶來說,只要設備接入系統后能夠正常工作就可以了,不需要知道這個設備是連接在系統的哪一個端口上。但是如果一個系統中同時有多個具有相同的VID和PID的設備接入,要對其中的每一臺設備進行單獨的測試,就有必要研究這個設備的接入方式了。
一般的研究方法,應該是順藤摸瓜,或者相反。我在查找了相關的介紹后,很少能夠看到完整的例子,特別是對于U盤這樣的設備,很少有人直接將最終系統中顯示的文件卷與USB端口的連接關系做成樹狀的關系圖顯示出來。昨天看了那個設備的卸載過程示例后,覺得應該可以實現的。因為可以從一個文件卷查找到起對應的連接關系。即從 U 盤的文件卷找到其連接的HUB,然后從HUB的端口出發,找到其所有的連接點(在設備管理器的資源中,顯示為總線關系)。后續應該可以繼續逆向尋找,一直找到主控制器。這樣就可以查清楚連接的脈絡。
看了微軟的 USB View 示例以及網友寫的 USB Port 示例,可以看出,查找USB設備,不一定非要從 USB 的設備接口類開始檢查,只要采用嘗試的方式,用 CreateFile 嘗試打開系統中名字為 HCD0, HCD1類似的名稱,就可以直接知道是不是有USB主控制器存在。此后通過 DeviceIoControl 函數,給主控制器發送 IOCTL_USB_GET_ROOT_HUB_NAME 命令,獲取 Root Hub 的名字。此后再次使用 CreateFile 的方式,打開 RootHub,用DeviceIoControl 給RootHub發送 IOCTL_USB_GET_NODE_INFORMATION 命令,取得該 Hub上端口信息。在端口信息的 HubDescriptors 中,包含了 NumOfPorts,即該 Hub 上的端口數量。同時,這個端口信息中包含了指向端口連接關系的指針數組。通過循環檢查的方式,使用 DeviceIoControl 給端口發送 IOCTL_USB_GET_NODE_CONNECTION_INFORMATION 命令,獲取該端口的連接關系信息表,其中的一個bConnected 即標識了是否有設備連接在該端口上。并且有一個 ConnectedIsHub的標志,反映該端口連接是下一級 Hub還是一般的設備。通過 GetDriverKeyName 函數,從 HubDevice 中獲得所連接的設備的驅動信息,包括了設備類Guid,設備的 PID,VID,連接速度等描述內容。采用循環的方式可以逐一查找所有已連接的設備。
如果要進一步查找其中的Hub設備所連接的信息,必須采用遞歸方法逐步深入到每一個Hub的下層,才可以獲得完整的設備連接信息。
知道了設備名稱,并無法獲取對應的映射文件卷的關系。此時還需要回頭從文件系統著手,用循環的方法,檢查系統中已經支持的文件卷多對應的設備,通過比對的方式與連接關系做對應。特別是對于一個連接口映射為多個文件卷的情形,可能有一部分是支持在文件系統中,而另一部分不一定顯示(如未分配驅動器符號或作為一個現有文件卷的連接等),則比較難于顯示了。
|