USB device & USB controller & USB passthrough

近期往 openstack 裏倒騰 USB passthrough[1],遂把 USB 知識做較爲全面的整理,以供分享。


USB device

        什麼是 USB device, 上圖機智的小萌狗就是 USB device,你的鼠標是 USB device, 鍵盤是 USB device,U 盤更是典型的 USB device。說了這麼多例子,還是得用一個專業的名詞一語概之,所謂 USB,即是 Universal Serial Bus(通用串行總線),它是用來連接 USB device 和計算機,從而實現 USB device 和計算機之間的通訊[2]

    當把 U 盤插入到計算機的 USB 口時,我們便能在操作系統中找到該 USB device 並使用之,是不是很簡單? 可對碼農來說,卻不簡單,簡直是複雜...... 下圖解釋了了 USB device 如何與計算機系統交互。USB device 不能直接和操作系統通信,它需要 USB controller interface 這座橋樑才能在硬件上接入到計算機上。HCD(Host Controller Device)則是則是硬件商向程序員提供的開發接口。

USB device 通過 USB controller 和計算機交互得遵守一套標準,這套標準我們稱之爲 USB 協議:

USB版本   最大傳輸速率   速率稱號   最大輸出電流   推出時間  
USB1.0   1.5Mbps(192KB/s)   低速(Low-Speed)   500mA   1996年1月  
USB1.1   12Mbps(1.5MB/s)   全速(Full-Speed)   500mA   1998年9月  
USB2.0   480Mbps(60MB/s)   高速(High-Speed)   500mA   2000年4月  
USB3.0   5-10Gbps(640MB/s)   超速(Super-Speed)   900mA   2008年11月  
注:部分 USB 2.0 Device 的速率爲全速(Full-speed)[3],比如很多 USBKey 便是全速的 USB2.0 device。

    常用的 USB 協議爲 USB1.1 和 USB 2.0,比如 U 盤一般爲 USB 2.0,由於 USB 2.0 是向下兼容的,所以 USB 2.0 的設備,也支持 USB 1.1。

USB controller

不僅 USB device 得遵守 USB 相關協議,USB controller 也必須遵守該協議。也就是說,針對 USB1.1 device,需要有對應的 USB controller (uhci)來支持,對於 USB2.0 device,也需要 USB controller(ehci) 來支持。USB controller 分爲以下四種類型[4]

1. OHCI(Open Host Controller Interface),它是開放的支持 USB1.1 和 Firewire(Apple) 的標準。和 UCHI 相比,OHCI 的硬件完成大部分工作,因此硬件設計複雜,而軟件驅動設計簡單。OHCI的另外一個缺點是它僅支持 32-bit,對於 64-bit 的操作系統,它需要 IOMMU 支持。
2. UHCI(Universal Host Controller Interface),是Intel主導的對USB1.x 的接口標準,與OHCI不兼容,支持全速和慢速設備。和 OHCI 相反,UHCI 硬件設計簡單,因此需要相對複雜的軟件驅動。UHCI 同樣僅支持 32 bit,對於 64 bit d的操作系統,需要 IOMMU 支持。UHCI的軟件驅動的任務重,需要做得比較複雜,但可以使用較便宜、較簡單的硬件的USB控制器。Intel和VIA使用UHCI,而其餘的硬件提供商使用OHCI。
3. EHCI(Enhanced Host Controller Interface),是Intel主導的專門用於支持 USB2.0 的高速接口標準,對於 USB 2.0 的全速設備,EHCI 無法支持。因此,一般的 PC 機都帶有兩個 USB 控制器,EHCI 和 UCHI。

4. xHCI(eXtensible Host Controller Interface)是最新的專門用於支持USB3.0的接口標準,它在速度,節能和虛擬化方面均有很大的提升,它支持 USB 各種速度標準(USB 3.1 SuperSpeed+, USB 3.0 SuperSpeed, USB 2.0 Low-, Full-, and High-speed, USB 1.1 Low- and Full-speed)。

Linux 相關命令

1). lsusb 查詢所有的 USB device

[root@test ~]# lsusb
Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 001 Device 002: ID 0627:0001 Adomax Technology Co., Ltd 

2). lsusb -t 查詢所有 USB device 層次信息情,lsusb -v 可查詢所有 USB device 詳情。
[root@test ~]# lsusb -t 
Bus# 1 
`-Dev# 1 Vendor 0x1d6b Product 0x0001 
`-Dev# 2 Vendor 0x0627 Product 0x0001

3). lspci |grep USB 查詢 USB controller
[root@test ~]# lspci |grep USB 
00:01.2 USB controller: Intel Corporation 82371SB PIIX3 USB [Natoma/Triton II] (rev 01)

4). 更爲詳細的信息可以通過查詢 USB 文件

[root@test ~]# cat  /proc/bus/usb/devices
T:  Bus=02 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12   MxCh= 3
B:  Alloc=  0/900 us ( 0%), #Int=  0, #Iso=  0
D:  Ver= 1.10 Cls=09(hub  ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=1d6b ProdID=0001 Rev= 3.00
S:  Manufacturer=Linux 3.0.15 ohci_hcd
S:  Product=s5p OHCI
S:  SerialNumber=s5p-ohci
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=  0mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
E:  Ad=81(I) Atr=03(Int.) MxPS=   2 Ivl=255ms

以上信息的含義如下[5]參見:kernel\Documentation\usb\proc_usb_info.txt:
T = 總線拓撲(Topology)結構(Lev, Prnt, Port, Cnt, 等),是指USB設備和主機之間的連接方式
B = 帶寬(Bandwidth)(僅用於USB主控制器)
D = 設備(Device)描述信息
P = 產品(Product)標識信息
S = 字符串(String)描述符
C = 配置(Config)描述信息 (* 表示活動配置)
I = 接口(Interface)描述信息
E = 端點(Endpoint)描述信息
一般格式:
d = 十進制數
x = 十六進制數
s = 字符串

拓撲信息
T:  Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd
|   |      |      |       |       |      |        |       |__最大子設備
|   |      |      |       |       |      |        |__設備速度(Mbps)
|   |      |      |       |       |      |__設備編號
|   |      |      |       |       |__這層的設備數
|   |      |      |       |__此設備的父連接器/端口
|   |      |      |__父設備號
|   |      |__此總線在拓撲結構中的層次
|   |__總線編號
|__拓撲信息標誌

帶寬信息
B:   Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd
|    |                       |         |__同步請求編號
|    |                       |__中斷請求號
|    |__分配給此總線的總帶寬
|__帶寬信息標誌

設備描述信息和產品標識信息

D:   Ver=x.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
|    |        |             |      |       |       |__配置編號
|    |        |             |      |       |______缺省終端點的最大包尺寸
|    |        |             |      |__設備協議
|    |        |             |__設備子類型
|    |        |__設備類型
|    |__設備USB版本
|__設備信息標誌編號#1

P:   Vendor=xxxx ProdID=xxxx Rev=xx.xx
|    |           |           |__產品修訂號
|    |           |__產品標識編碼
|    |__製造商標識編碼
|__設備信息標誌編號#2

串描述信息
S:   Manufacturer=ssss
|    |__設備上讀出的製造商信息
|__串描述信息
S:   Product=ssss
|    |__設備上讀出的產品描述信息,對於USB主控制器此字段爲"USB *HCI Root Hub"
|__串描述信息
S:   SerialNumber=ssss
|    |__設備上讀出的序列號,對於USB主控制器它是一個生成的字符串,表示設備標識
|__串描述信息

配置描述信息
C:   #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
|    |       |       |      |__最大電流(mA)
|    |       |       |__屬性
|    |       |__配置編號
|    |__接口數
|__配置信息標誌

接口描述信息(可爲多個)
I:   If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
|    |      |      |       |             |      |       |__驅動名
|    |      |      |       |             |      |__接口協議
|    |      |      |       |             |__接口子類
|    |      |      |       |__接口類
|    |      |      |__端點數
|    |      |__可變設置編號
|    |__接口編號
|__接口信息標誌

端點描述信息
E:   Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
|    |        |            |         |__間隔
|    |        |            |__終端點最大包尺寸
|    |        |__屬性(終端點類型)
|    |__終端點地址(I=In,O=Out)
|__終端點信息標誌

Python 相關庫

在 pip 中找到兩個和 usb 相關 package,分別爲 pyUSB, usbid。

usbid: 實現方式 too young, too simple,僅僅通過讀取USB 設備文件來獲取 USB device 信息。
pyUSB:  通過調用 libusb1.0.so 獲取 usb device 設備信息,但是無法獲取速度相關信息。查閱 libusb 代碼發現 libusb 支持獲取速度信息,於是補充了 pyUSB 獲取 usb device 速度信息 patch https://github.com/DeliangFan/pyusb

Libvirt USB passthrough

1).Libvirt USB Controller

Libvirt 支持多種 USB controller 設備
下述xml 描述了兩個 USB controller,分別爲 ehci 和 uhci。
<controller type='usb' index='0' model='ehci'/>
<controller type='usb' index='1' model='piix3-uhci'>

2). Attach USB device to vm

virsh attach-device domain_id usb_ehci.xml
把 USB device attach 到 ehci controler, port 對應 usb controler 的 index。
cat usb_echi.xml
<hostdev mode='subsystem' type='usb' managed='yes'>
   <source>
       <vendor id='0x0763'/>
       <product id='0x202a'/>
       <address bus='1' device='3' />
   </source>
   <address type='usb' bus='0' port='1'/>
</hostdev>
virsh attach-device domain_id usb_uhci.xml
把 USB device attach 到 uhci controler 的
cat usb_uchi.xml
<hostdev mode='subsystem' type='usb' managed='yes'>
   <source>
       <vendor id='0x0763'/>
       <product id='0x202a'/>
       <address bus='1' device='3' />
   </source>
   <address type='usb' bus='0' port='0'/>
</hostdev>

3). Detach USB device from vm
virsh detach-device domain_id usb_ehci.xml

參考資料

1.USB passthrough blueprint
2.Gentoo Linux USB 指南
3.HP 全速 USB2.0 Device
4.維基百科 USB Controller 介紹
5.Linux USB device 參數說明
6.Libvirt USB Controller xml format
7.Libvirt USB Device xml format

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章