1. 簡介
USB gadget是什麼?Linux-USB Gadget 驅動框架(以下簡稱 Gadget)實現了USB 協議定義的設備端的軟體功能。相對於 Linux USB 主機端(Host) 驅動而言, Gadget 驅動出現較晚,它出現在2.4.23 以後。
Gadget 框架提出了一套標準 API, 在底層, USB 設備控制器(USB Device Controller, UDC)驅動則實現這一套 API, 不同的 UDC (通常是 SOC 的一部分) 需要不同的驅動, 甚至基於同樣的 UDC 的不同板子也需要進行代碼修改。這一層我們可以稱之為平臺相關層。
基於 API, Gadget 驅動實現了一套硬體無關的功能,這基本上可以對應到 USB 協議裡 的各種 USB Class, 也有比如 USB Gadget Generic Serial 驅動,沒有對應的 Class。當然,Gadget 驅動還是受限於底層提供的功能的。比如 某些 Class 需要 USB Isochronous 端點,這時我們就不能支持該 Class。 普通的 Gadget 驅動只實現一個功能(比如u 盤,usb 網卡)。複合設備可以支持多個功能,後面將仔細研究一下複合設備的實現。像智慧型手機, PDA這樣的設備,硬體支持較豐富的端點、DMA Buffer, 給軟體提了支持複合功能的基礎。
有兩點值得注意,第一是 usb gaget 驅動框架不象 usb 主機端有 usb core 的概念,usb 主機可能支持成百類型的外設,把通用功能抽象出來很有意義。Usb device 端則通常沒有這個需求,一些通用功能抽象在一些 Helper 函數裡就可以了。第二是 usb 2.0 裡提出了 OTG 的概念,可以在同一接口上支持 host 以及 device 功能。
2. 控制器驅動
常見的 usb device 有 U 盤, usb 滑鼠、鍵盤,usb 藍牙模塊,usb 讀卡器,等等。這些設備比較簡單,通常不會運行Linux。運行Linux Gadget 的通常是一些集成 CPU 以及很多外設接口的 SOC (System-on-Chip), 其中 CPU 通常為 32 bit 的 CPU, 並且 udc 也是該 SOC 的一部分( 順帶還有 DMA 通道,FIFO)。
Linux 標準內核裡支持各主流 SOC 的 udc 驅動,make menuconfig 一下可以看到具體列表,其中值得一提的是 dummy_hcd, 它是一個軟體模擬的 udc, 在開發新的 gadget 驅動時很有幫助。
控制器驅動處理很少的 USB 控制請求(主要由硬體負責的部分)。其它所有的控制請求,比如返回描述符,設置當前配置,由 Gadget Driver 完成。控制器驅動一個主要責任就是負責管理各個端點的 I/O 隊列,在 Gadget Driver 的 buffer 和硬體buffer 之間傳輸數據(通常是通過 DMA)。
我們前面提過,上層 Gadget 驅動能夠實現什麼功能要依賴底層提供的硬體條件。比如一個複合設備需要至少 5 個端點,這些硬體特性通過一組 gadget_is_*()函數實現。
3. Gadget 驅動
基於底層提供的資源, Gadget 驅動可以運行在各種硬體平臺上。重要的驅動有:
Gadget Zero, 類似於 dummy hcd, 該驅動用於測試 udc 驅動。它會幫助您通過 USB-IF 測試。
Ethernet over USB, 該驅動模擬乙太網網口,它支持多種運行方式:
CDC Ethernet: usb 規範規定的 Communications Device Class 「Ethernet Model」 protocol。
CDC Subset: 對硬體要求最低的一種方式,主要是 Linux 主機支持該方式。
RNDIS: 微軟公司對 CDC Ethernet 的變種實現。
File-backed Storage Gadget最常見的 U 盤功能實現。
Serial Gadget 實現,包括: Generic Serial 實現(只需要Bulk-in/Bulk-out端點+ep0)和CDC ACM 規範實現。
Gadget Filesystem, 將 Gadget API 接口暴露給應用層,以便在應用層實現user mode driver。
MIDI: 暴露ALSA接口,提供 recording 以及 playback 功能。
4. t軟體結構
USB Gadget軟體結構總共分為三層:
a.UDC(USB Device Controller)層
這一層是與硬體相關層。以S3C2410為例,其作為一個linux設備在這一層是作為platform設備而註冊到linux設備模型中的。S3C2410是集成的USB設備控制器,所以就是採用platform驅動的形式來註冊的。如果系統是外接的USB設備控制器,那麼則會採用相應總線的註冊形式,比如PCI等。
b.USB設備層
USB設備層,雖然名字上與設備相關。但是屬於硬體無關層。這一層的功能是隔離Gadget功能驅動與硬體相關層。使得功能驅動直接與USB設備層交互不用考慮硬體的相關細節。還有USB設備層提供了USB設備的一些基本數據結構,不同的Gadget功能驅動可以共同調用。如果沒有這一層,則每一個功能驅動都需要實現自己的USB設備,導致了代碼重用率很高。這一層向下與UDC層進行交互,向上與Gadget功能驅動層進行交互。在UDC層已經介紹了USB設備層向下與UDC層交互方式主要是通過調用usb_gadget_register_driver(struct usb_gadget_driver *driver),這個函數是UDC層提供的。而這個函數傳遞的參數就是一個usb_gadget_driver的結構體。
c.Gadget功能驅動層
Gadget 功能驅動層是USB Gadget軟體結構的最上層。主要是實現USB設備的功能,這一層通常與linux內核的其他層有密切的聯繫。模擬網卡或者串口的gadget就與文件系統層與塊IO層有著聯繫。
下面的圖很好的說明了整個USB-Gadget軟體架構: