2009年8月10日 星期一

淺談 USB 通訊架構之定義(二)

Standard
之前『淺談 USB 通訊架構之定義(一)』已經提過 USB 大致上的概念和一些特性,以及如何從 Linux 上去嘗試驗證 USB Device 上的 Information,但還尚未談及 USB Device 是如何與 USB Host 做溝通。而且,初始化的過程也很重要,該過程會讓一個 USB Device 描述自己的『模式(Configuration)』和『介面(Interface)』以及更多配置上的關鍵訊息。雖然這些初始化過程和定義繁雜,但是拜 OS 優良的包裝所賜,一般驅動程式都可以假設已知或是透過簡單的 API 去取得這些資訊以進行開發,因為大多數初始化動作會自動由 OS Kernel 和 Firmware 所完成。

簡單的 USB Device 初始化流程
  1. 插上 USB 裝置
  2. Host 請裝置報告裝置描述資訊(Device Descriptors)』(此過程又稱為 Enumeration
    • Device Descriptors 得知模式的數量(bNumConfigurations)
  3. Host 請裝置回報模式的描述資訊(Configuration Descriptors)
    • Configuration Descriptors 得知介面的數量(bNumInterfaces)
  4. Host 請裝置回報介面的描述資訊(Interface Descriptors)
    • Interface Descriptors 得知端點的數量(bNumEndpoints)
  5. Host 請裝置回報端點的描述資訊(Endpoint Descriptors)
    • Endpoint Descriptors 得知該端點的資料傳輸模式(bmAttributes)』等訊息
  6. 等待驅動程式進行後續處理
整個 USB Device 的描述結構可以圖表示:
當然,若不是 USB Device 設計者或是 USB Host Controller 晶片的 Firmware/Driver 開發人員,可以不用知道這麼多過程細節,因為無論是 Linux 還是其他作業系統,它們都會將這些最低階的過程包裝起來,等著驅動程式去使用,而 Linux Kernel 上負責此任務的就被稱為『USB core』。

註:因為古老的 DOS 在設計上沒有 USB 的支援,故沒有這種中間層的包裝,若要在上面開發 USB 驅動程式,除了 USB Device 驅動程式要撰寫之外,還要苦命的先開發 USB Host Controller(UHCI、OHCI、EHCI...)的驅動程式。


Endpoint(端點) 的用途和定義


USB Device 真正和 Host 間傳輸資料是透過『Endpoint』,等到 USB Device 初始化完,剩下的就是使用 Endpoint 與 USB Device 溝通,這也是 USB Device 驅動程式真正開始要發威的時候。

Endpoint 的傳輸形態分為四種:
  • Control

    通常用來控制 USB Device 所使用,只能用在 endpoint 0 上。各種 USB Device(包括了 USB Host Controller 上的 Root Hub) 上都有 endpoint 0 做傳送命令、取得硬體資訊等動作。在 USB 協定中,Control 一定會有足夠頻寬完成每次傳輸。

  • Bulk

    大量且安全的傳輸,通常會應用在不可失真且大資料量的通訊,如:隨身碟。USB 協定中,並不保證 Bulk 會有一定的頻寬,所以若是當下 USB bus 頻寬不夠,資料會被分批進行傳輸。

  • Isochronous

    大量且穩定持續但不保證安全的傳輸,也就是不會檢查資料是否完整通過,可應用串流影音等可容許資料失真的地方,如:麥克風。要注意的是,此種傳輸方式會搶走 Bulk 的頻寬。

  • Interrupt

    Host 的輪詢機制會對所有 USB Device 請求 Interrupt 傳輸,若此時 USB Device 有需要 Interrupt 傳輸,便可開始以固定的速率傳送少量資料,通常應用在鍵盤、滑鼠此種 HID 上。

USB Device 的
描述資訊

前面提到,USB Device 的初始化是在不斷反覆取得裝置資訊中完成的,而無論是哪一個 Descriptors,都有一個固定的資料結構,基本型如下表:

偏移量(Offset)

欄位名稱(Field)

大小(Size)

值的類型(Value)

欄位說明(Description)

0

bLength

1

數值

整個描述表的大小(單位 Bytes)

1

bDescriptionType

1

常數

描述表類型

2

...

n


描述表內容,根據不同類型的表有不同定義


而其中描述表類型之常數定義為:
  • 0x01:Device Descriptor
  • 0x02:Configuration Descriptor
  • 0x03:String Descriptor
  • 0x04:Interface Descriptor
  • 0x05:Endpoint Descriptor
更多的資訊,也可以參考以下網站:
http://www.beyondlogic.org/usbnutshell/usb5.htm

註:以 Linux 為例,通常系統已經將大多數裝置資訊匯整在 sysfs 之下,或是有現成 API 可以取得資料結構,其實對於普通的驅動程式開發者來說,並不用太去瞭解最原始的描述定義,只要知道從何可以取得必要的資訊即可。

後記

基本觀念瞭解到這,其實大致上就足夠開始開發 USB Device 的驅動程式了,剩下的問題只是如何使用 URB(USB Request block) 去和 endpoint 做溝通和傳輸罷了。