13.1. USB 設備基礎知識

2018-02-24 15:50 更新

13.1.?USB 設備基礎知識

一個 USB 設備是一個非常復雜的事物, 如同在官方的 USB 文檔(可從 http://www.usb.org 中得到)中描述的. 幸運的是, Linux 提供了一個子系統(tǒng)稱為 USB 核, 來處理大部分復雜的工作. 這一章描述驅動和 USB 核之間的交互. 圖USB 設備概覽顯示了 USB 設備如何包含配置, 接口, 和端點, 以及 USB 驅動如何綁定到 USB 接口, 而不是整個 USB 設備.

13.1.1.?端點

USB 通訊的最基本形式是通過某些稱為 端點 的. 一個 USB 端點只能在一個方向承載數(shù)據(jù), 或者從主機到設備(稱為輸出端點)或者從設備到主機(稱為輸入端點). 端點可看作一個單向的管道.

一個 USB 端點可是 4 種不同類型的一種, 它來描述數(shù)據(jù)如何被傳送:

CONTROL
控制端點被用來允許對 USB 設備的不同部分存取. 通常用作配置設備, 獲取關于設備的信息, 發(fā)送命令到設備, 或者獲取關于設備的狀態(tài)報告. 這些端點在尺寸上常常較小. 每個 USB 設備有一個控制端點稱為"端點 0", 被 USB 核用來在插入時配置設備. 這些傳送由 USB 協(xié)議保證來總有足夠的帶寬使它到達設備.

INTERRUPT
中斷端點傳送小量的數(shù)據(jù), 以固定的速率在每次 USB 主請求設備數(shù)據(jù)時. 這些端點對 USB 鍵盤和鼠標來說是主要的傳送方法. 它們還用來傳送數(shù)據(jù)到 USB 設備來控制設備, 但通常不用來傳送大量數(shù)據(jù). 這些傳送由 USB 協(xié)議保證來總有足夠的帶寬使它到達設備.

BULK
塊端點傳送大量的數(shù)據(jù). 這些端點常常比中斷端點大(它們一次可持有更多的字符). 它們是普遍的, 對于需要傳送不能有任何數(shù)據(jù)丟失的數(shù)據(jù). 這些傳送不被 USB 協(xié)議保證來一直使它在特定時間范圍內(nèi)完成. 如果總線上沒有足夠的空間來發(fā)送整個 BULK 報文, 它被分為多次傳送到或者從設備. 這些端點普遍在打印機, 存儲器, 和網(wǎng)絡設備上.

ISOCHRONOUS
同步端點也傳送大量數(shù)據(jù), 但是這個數(shù)據(jù)常常不被保證它完成. 這些端點用在可以處理數(shù)據(jù)丟失的設備中, 并且更多依賴于保持持續(xù)的數(shù)據(jù)流. 實時數(shù)據(jù)收集, 例如音頻和視頻設備, 一直都使用這些端點.

控制和塊端點用作異步數(shù)據(jù)傳送, 無論何時驅動決定使用它們. 中斷和同步端點是周期性的. 這意味著這些端點被設置來連續(xù)傳送數(shù)據(jù)在固定的時間, 這使它們的帶寬被 USB 核所保留.

USB 端點在內(nèi)核中使用結構 struct usb_host_endpoint 來描述. 這個結構包含真實的端點信息在另一個結構中, 稱為 struct usb_endpoint_descriptor. 后者包含所有的 USB-特定 數(shù)據(jù), 以設備自身特定的準確格式. 驅動關心的這個結構的成員是:

bEndpointAddress
這是這個特定端點的 USB 地址. 還包含在這個 8-位 值的是端點的方向. 位掩碼 USB_DIR_OUT 和 USB_DIR_IN 可用來和這個成員比對, 來決定給這個端點的數(shù)據(jù)是到設備還是到主機.

bmAttributes
這是端點的類型. 位掩碼 USB_ENDPOINT_XFERTYPE_MASK 應當用來和這個值比對, 來決定這個端點是否是 USB_ENDPOINT_XFER_ISOC, USB_ENDPOINT_XFER_BULK, 或者是類型 USB_ENDPOINT_XFER_INT. 這些宏定義了同步, 塊, 和中斷端點, 相應地.

wMaxPacketSize
這是以字節(jié)計的這個端點可一次處理的最大大小. 注意驅動可能發(fā)送大量的比這個值大的數(shù)據(jù)到端點, 但是數(shù)據(jù)會被分為 wMaxPakcetSize 的塊, 當真正傳送到設備時. 對于高速設備, 這個成員可用來支持端點的一個高帶寬模式, 通過使用幾個額外位在這個值的高位部分. 關于如何完成的細節(jié)見 USB 規(guī)范.

bInterval
如果這個端點是中斷類型的, 這個值是為這個端點設置的間隔, 即在請求端點的中斷之間的時間. 這個值以毫秒表示.

這個結構的成員沒有一個"傳統(tǒng)" Linux 內(nèi)核的命名機制. 這是因為這些成員直接對應于 USB 規(guī)范中的名子. USB 內(nèi)核程序員認為使用規(guī)定的名子更重要, 以便在閱讀規(guī)范時減少混亂, 不必使這些名子對 Linux 程序員看起來熟悉.

13.1.2.?接口

USB 端點被綁在接口中. USB 接口只處理一類 USB 邏輯連接, 例如一個鼠標, 一個鍵盤, 或者一個音頻流. 一些 USB 設備有多個接口, 例如一個 USB 揚聲器可能有 2 個接口: 一個 USB 鍵盤給按鈕和一個 USB 音頻流. 因為一個 USB 接口表示基本的功能, 每個 USB 驅動控制一個接口; 因此, 對揚聲器的例子, Linux 需要 2 個不同的驅動給一個硬件設備.

USB 接口可能有預備的設置, 是對接口參數(shù)的不同選擇. 接口的初始化的狀態(tài)是第一個設置, 0 號. 預備的設置可用來以不同方式控制單獨的端點, 例如來保留不同量的 USB 帶寬給設備. 每個有同步端點的設備使用預備設備給同一個接口.

USB 接口在內(nèi)核中使用 struct usb_interface 結構來描述. 這個結構是 USB 核傳遞給 USB 驅動的并且是 USB 驅動接下來負責控制的. 這個結構中的重要成員是:

struct usb_host_interface *altsetting
一個包含所有預備設置的接口結構的數(shù)組, 可被挑選給這個接口. 每個 struct usb_host_interface 包含一套端點配置, 如同由 struct usb_host_endpoint 結構所定義的. 注意這些接口結構沒有特別的順序.

unsigned num_altsetting
由 altsetting 指針指向的預備設置的數(shù)目.

struct usb_host_interface *cur_altsetting
指向數(shù)組 altsetting 的一個指針, 表示這個接口當前的激活的設置.

int minor
如果綁定到這個接口的 USB 驅動使用 USB 主編號, 這個變量包含由 USB 核心安排給接口的次編號. 這只在一次成功地調用 usb_register_dev (本章稍后描述)之后才有效.

在 struct usb_interface 結構中有其他成員, 但是 USB 驅動不需要知道它們.

13.1.3.?配置

USB 接口是自己被捆綁到配置的. 一個 USB 設備可有多個配置并且可能在它們之間轉換以便改變設備的狀態(tài). 例如, 一些允許固件被下載到它們的設備包含多個配置來實現(xiàn)這個. 一個配置只能在一個時間點上被使能. Linux 處理多配置 USB 設備不是太好, 但是, 幸運的是, 它們很少.

linux 描述 USB 配置使用結構 struct usb_host_config 和整個 USB 設備使用結構 struct usb_device. USB 設備驅動通常不會需要讀寫這些結構的任何值, 因此它們在這里沒有詳細定義. 好奇的讀者可在內(nèi)核源碼樹的文件 include/linux/usb.h 中找到對它們的描述.

一個 USB 設備驅動通常不得不轉換數(shù)據(jù)從給定的 struct usb_interface 結構到 struct usb_device 結構, USB 核心需要給很多的函數(shù)調用. 為此, 提供有函數(shù) interface_to_usbdev. 在以后, 希望所有的當前需要一個 struct usb_device 的 USB 調用, 將被轉換為采用一個 struct usb_interface 參數(shù), 并且不會要求驅動做這個轉換.

所以總結, USB 設備是非常復雜的, 并且由許多不同邏輯單元組成. 這些單元之間的關系可簡單地描述如下:

  • 設備通常有一個或多個配置.

  • 配置常常有一個或多個接口

  • 接口常常有一個或多個設置.

  • 接口有零或多個端點.

[45] 本章的多個部分是基于內(nèi)核中的給 Linux 內(nèi)核 USB 代碼的文檔, 這些代碼由內(nèi)核 USB 開發(fā)者編寫并且以 GPL 發(fā)布.

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號