淺談 USB 通訊架構之定義(二)
之前『淺談 USB 通訊架構之定義(一)』已經提過 USB 大致上的概念和一些特性,以及如何從 Linux 上去嘗試驗證 USB Device 上的 Information,但還尚未談及 USB Device 是如何與 USB Host 做溝通。而且,初始化的過程也很重要,該過程會讓一個 USB Device 描述自己的『模式(Configuration)』和『介面(Interface)』以及更多配置上的關鍵訊息。雖然這些初始化過程和定義繁雜,但是拜 OS 優良的包裝所賜,一般驅動程式都可以假設已知或是透過簡單的 API 去取得這些資訊以進行開發,因為大多數初始化動作會自動由 OS Kernel 和 Firmware 所完成。
簡單的 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 的傳輸形態分為四種:
USB Device 的描述資訊
前面提到,USB Device 的初始化是在不斷反覆取得裝置資訊中完成的,而無論是哪一個 Descriptors,都有一個固定的資料結構,基本型如下表:
而其中描述表類型之常數定義為:
http://www.beyondlogic.org/usbnutshell/usb5.htm
註:以 Linux 為例,通常系統已經將大多數裝置資訊匯整在 sysfs 之下,或是有現成 API 可以取得資料結構,其實對於普通的驅動程式開發者來說,並不用太去瞭解最原始的描述定義,只要知道從何可以取得必要的資訊即可。
後記
基本觀念瞭解到這,其實大致上就足夠開始開發 USB Device 的驅動程式了,剩下的問題只是如何使用 URB(USB Request block) 去和 endpoint 做溝通和傳輸罷了。
簡單的 USB Device 初始化流程
- 插上 USB 裝置
- Host 請裝置報告『裝置描述資訊(Device Descriptors)』(此過程又稱為 Enumeration)
- 由 Device Descriptors 得知『模式的數量(bNumConfigurations)』
- Host 請裝置回報『模式的描述資訊(Configuration Descriptors)』
- 由 Configuration Descriptors 得知『介面的數量(bNumInterfaces)』
- Host 請裝置回報『介面的描述資訊(Interface Descriptors)』
- 由 Interface Descriptors 得知『端點的數量(bNumEndpoints)』
- Host 請裝置回報『端點的描述資訊(Endpoint Descriptors)』
- 由 Endpoint Descriptors 得知『該端點的資料傳輸模式(bmAttributes)』等訊息
- 等待驅動程式進行後續處理
當然,若不是 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 做溝通和傳輸罷了。
亲,是否 有后续的URB通讯文章呢?
回覆刪除