乾坤合一:Linux裝置驅動之USB主機和裝置驅動

李輝發表於2016-05-29

這一章從主機側角度看到的USB 主機控制器驅動和裝置驅動從主機側的角度而言,需要編寫的USB 驅動程式包括主機控制器驅動和裝置驅動兩類,USB 主機控制器驅動程式控制插入其中的USB 裝置,而USB 裝置驅動程式控制該裝置如何作為從裝置與主機通訊。

1. Linux USB驅動層次

1.1 主機側與裝置側USB 驅動

USB 採用樹形拓撲結構,每條匯流排上只有一個主機控制器,負責協調主機和裝置間的通訊,而裝置不能主動向主機傳送任何訊息。

1.2 裝置、配置、介面、端點

在USB 裝置的邏輯組織中,包含裝置、配置、介面和端點4 個層次,每個USB 裝置都提供了不同級別的配置資訊,可以包含一個或多個配置,不同的配置使裝置表現出不同的功能組合,配置由多個介面組成,介面由多個端點組成,代表一個基本的功能,是USB 裝置驅動程式控制的物件,如下圖是USB 裝置、配置、介面和端點之間的關係。

裝置描述符:關於裝置的通用資訊,如供應商ID 、產品ID 和修訂ID,支援的裝置類、子類和適用的協議以及預設端點的最大包大小等。在Linux 核心中,USB 裝置用 usb_device 結構體來描述,USB 裝置描述符定義為usb_device_descriptor 結構體,其程式碼如下:

配置描述符:此配置中的介面數、支援的掛起和恢復能力以及功率要求。USB配置在核心中使用usb_host_config 結構體描述,USB 配置描述符定義為結構體usb_config_descriptor,其程式碼如下:

介面描述符:介面類、子類和適用的協議,介面備用配置的數目和端點數目。USB介面在核心中使用 usb_interface 結構體描述,USB 介面描述符定義為結構體 usb_interface_descriptor,其程式碼如下:

端點描述符:端點地址、方向和型別,支援的最大包大小,如果是中斷型別的端點則還包括輪詢頻率。在 Linux 核心中,U SB 端點使用 usb_host_endpoint 結構體來描述,USB端點描述符定義為 usb_ endpoint_ descriptor 結構體,其程式碼如下:

字串描述符:在其他描述符中會為某些欄位提供字串索引,它們被用來檢索描述性字串,可以以多種語言形式提供。字串描述符是可選的,有的裝置有,有的裝置沒有 ,字元 串描述符對應於usb_string_ descriptor 結構體,其程式碼如下:

2 USB主機驅動

USB 主機控制器有 3 種規格:OHCI (Open Host Controller Interface) 、UHCI (Universal Host Controller Interface) 和EHCI (Enhanced Host Controller Interface) 。

2.1 主機控制器驅動

在Linux 核心中,用usb_hcd 結構體描述USB 主機控制器驅動,它包含USB 主機控制器的 “家務”資訊、硬體資源、狀態描述和用於操作主機控制器的 hc_driver等,其程式碼如下:

Linux中採用以下函式建立HCD:

以下函式用來增加和移除:

2.2 OHCI 主機控制器驅動

OHCI HCD 驅動屬於HCD 驅動的例項,它定義了一個ohci_hcd 結構體,使用如下行內函數可實現usb_hcd 和ohci_hcd 的相互轉換:

從usb_hcd 得到ohci_hcd 只是取得“私有”資料,而從ohci_hcd 得到usb_hcd 則是通過container_of()從結構體成員獲得結構體指,使用如下函式可初始化OHCI 主機控制器:

如下函式分別用於開啟、停止及復位OHCI 控制器:

3 USB裝置驅動

3.1 USB裝置驅動整體結構

有以下裝置類

  • 音訊裝置類。
  • 通訊裝置類。
  • HID (人機介面)裝置類。
  • 顯示裝置類。
  • 海量儲存裝置類。
  • 電源裝置類。
  • 列印裝置類。
  • 集線器裝置類。

Linux 核心為各類USB 裝置分配了相應的裝置號,核心中提供了USB 裝置檔案系統 (usbdevfs,Linux 2.6 改為usbfs,即USB 檔案系統),它和/proc 類似,都是動態產生的。通過在/etc/fstab 檔案中新增如下一行:

或者輸入命令:

可以實現USB 裝置檔案系統的掛載。

此外,在sysfs 檔案系統中,同樣包含了USB 相關資訊的描述,但只限於介面級別。USB 裝置和USB 介面在sysfs 中均表示為單獨的USB 裝置,其目錄命名規則如下:

根集線器-集線器埠號 (-集線器埠號-…):配置.介面。

3.2 USB請求塊(URB)

USB 請求塊 (USB request block,urb )是USB 裝置驅動中用來描述與USB 裝置通訊所用的基本載體和核心資料結構,非常類似於網路裝置驅動中的sk_buff 結構體,是USB 主機與裝置通訊的 “電波”,urb 結構體,程式碼如下:

USB 裝置中的每個端點都處理一個urb 佇列,在佇列被清空之前,一個urb 的典型生命週期有以下幾個過程:

  1. 被一個 USB裝置驅動建立
  2. 初始化,被安排給一個特定USB 裝置的特定端點
  3. 被USB 裝置驅動提交給USB
  4. 提交由USB 核心指定的USB 主機控制器驅動。
  5. 被USB 主機控制器處理,進行一次到USB 裝置的傳送。
  6. 當urb 完成,USB 主機控制器驅動通知USB 裝置驅動

3.3 簡單的批量與控制URB

1)usb_bulk_msg()

usb_bulk_msg()函式建立一個USB 批量urb 並將它傳送到特定裝置,這個函式是同步的,它一直等待urb 完成後才返回。usb_bulk_msg()函式的原型為:


// 如果函式呼叫成功,返回0 ;否則,返回1 個負的錯誤值。

2 )usb_control_msg()函式

usb_control_msg() 函式與 usb_bulk_msg() 函式類似,不過它提供驅動傳送和結束USB 控制資訊而非批量資訊的能力,該函式的原型為:

3) 探測和斷開函式

在USB 裝置驅動usb_driver 結構體的探測函式中,應該完成如下工作:

  • 探測裝置的端點地址、緩衝區大小,初始化任何可能用於控制 USB 裝置的資料結構。
  • 把已初始化資料結構的指 儲存到介面裝置中
  • 註冊USB 裝置

對探測函式的呼叫發生在USB 裝置被安裝且USB 核心認為該驅動程式與安裝的USB 裝置對應時 (usb_driver 的id_table 成員在此時發揮作用),而對斷開函式的呼叫則發生在驅動因為種種原因不再控制該裝置的時候。對這兩個函式的呼叫都是在核心執行緒中進行的.

4) USB 骨架程式

Linux 核心原始碼中的 driver/usb/usb-skeleton.c 檔案為我們提供了一個最基礎的USB 驅動程式,即USB 骨架程式,可被看做一個最簡單的USB 裝置驅動例項。儘管USB驅動驅動程式千差萬別,但是骨架程式萬變不離其宗。這裡我也不多介紹啦~

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

任選一種支付方式

乾坤合一:Linux裝置驅動之USB主機和裝置驅動 乾坤合一:Linux裝置驅動之USB主機和裝置驅動

相關文章