通用串行總線(USB)是主機和外圍設(shè)備之間的一種連接。
最新的USB規(guī)范修訂增加了理論上高達480Mbps的高速連接。
從拓撲上來看,一個USB子系統(tǒng)是一棵由幾個點對點的連接構(gòu)建而成的樹。
這些連接是連接設(shè)備和集線器(hub)的四線電纜(底線、電源、兩根信號線)。
USB主控制器(host controller)負責詢問每一個USB設(shè)備是否有數(shù)據(jù)需要發(fā)送。
USB總線是一個單主方式的實現(xiàn),即主機輪詢各種不同的外圍設(shè)備。
USB總線的特性:
*具有固定的數(shù)據(jù)傳輸帶寬的能力
*只擔當設(shè)備和主控制器之間通信通道的角色,對發(fā)送數(shù)據(jù)的結(jié)構(gòu)沒有要求
USB協(xié)議規(guī)范定義了一套任何特定類型的設(shè)備都可以遵循的標準。
如果一個設(shè)備遵循該標準,就不需要一個特殊的驅(qū)動程序。
這些不同的特定類型稱為類(class),
包括存儲設(shè)備、鍵盤、鼠標、游戲桿、網(wǎng)絡設(shè)備和調(diào)制解調(diào)器。
對于不符合這些類的其他類型的設(shè)備,需要針對特定的設(shè)備編寫一個特定的驅(qū)動程序。
如視頻設(shè)備。
Linux內(nèi)核支持兩種類型的USB驅(qū)動程序:
宿主(host)系統(tǒng)上的驅(qū)動程序和設(shè)備(device)上的驅(qū)動程序。
宿主系統(tǒng)的USB驅(qū)動程序控制插入其中的USB設(shè)備,
而USB設(shè)備的驅(qū)動程序控制該設(shè)備如何作為一個USB設(shè)備和主機通信。
用 戶
|
塊設(shè)備層
|
USB設(shè)備驅(qū)動程序
|
USB核心
|
USB主控制器
|
硬 件
USB核心為USB驅(qū)動程序提供了一個用于訪問和控制USB硬件的接口,
而不必考慮系統(tǒng)當前存在的各種不同類型的USB硬件控制器。
----------------------------------
USB設(shè)備基礎(chǔ)
本章描述驅(qū)動程序和USB核心之間的接口。
USB驅(qū)動程序
|
端點 端點 端點
|
接 口
|
配 置
|
設(shè) 備
---------
端點
USB通信最基本的形式是通過一個名為端點(endpoint)的東西,
包括:
*輸出端點
*輸入端點
端點可以看作單向的管道。
USB端點有4種不同的類型,其傳送數(shù)據(jù)的方式不同:
*控制
*中斷
*批量
*等時
內(nèi)核中使用struct usb_host_endpoint結(jié)構(gòu)體來描述USB端點。
該結(jié)構(gòu)體在另一個名為struct usb_endpoint_descriptor
的結(jié)構(gòu)體中包含了真正的端點信息。
后一個結(jié)構(gòu)體包含了所有的USB特定的數(shù)據(jù),
這些數(shù)據(jù)的格式是由設(shè)備自己定義的。
該結(jié)構(gòu)體中驅(qū)動程序需要關(guān)心的字段有:
bEndpointAddress
特定端點的USB地址。這個8位的值中還包含了端點的方向。
結(jié)合位掩碼USB_DIR_OUT和USB_DIR_IN來使用,以確定端點的數(shù)據(jù)
是傳向設(shè)備還是主機。
bmAttributes
端點的類型。該值結(jié)合位掩碼USB_ENDPOINT_XFERTYPE_MASK來使用,
以確定此端點的類型是USB_ENDPOINT_XFER_ISOC、USB_ENDPOINT_XFER_BULK
還是USB_ENDPOINT_XFER_INT。分別表示等時、批量和中斷端點。
wMaxPacketSize
該端點一次可以處理的最大字節(jié)數(shù)。
bInterval
如果端點是中斷類型,該值是端點的間隔設(shè)置。
--------
接口
USB端點被捆綁為接口。
USB接口只處理一種USB邏輯連接。
一些USB設(shè)備具有多個接口,例如
USB揚聲器可以包括兩個接口:一個USB鍵盤接口和一個USB音頻流接口。
一個USB接口代表了一個基本功能,每個USB驅(qū)動程序控制一個接口。
以揚聲器為例,Linux需要兩個不同的驅(qū)動程序來處理一個硬件設(shè)備。
內(nèi)核使用struct usb_interface結(jié)構(gòu)體來描述USB接口。
USB核心把該結(jié)構(gòu)體傳遞給USB驅(qū)動程序,
之后由USB驅(qū)動程序來負責控制該結(jié)構(gòu)體。
該結(jié)構(gòu)體的重要字段有:
struct usb_host_interface *altsetting
一個接口結(jié)構(gòu)體數(shù)組,包含了所有可能用于該接口的可選設(shè)置。
unsigned num_altsetting
altsetting指針所指的可選設(shè)置的數(shù)量。
struct usb_host_interface *cur_altsetting
指向altsetting數(shù)組內(nèi)部的指針,表示該接口的當前活動設(shè)置。
int minor
如果捆綁到該接口的USB驅(qū)動程序使用USB主設(shè)備號,
這個變量包含USB核心分配給該接口的次設(shè)備號。
------------
配置
USB接口本身被捆綁為配置。
一個USB設(shè)備可以有多個配置,而且可以在配置之間切換以改變設(shè)備的狀態(tài)。
Linux使用struct usb_host_config結(jié)構(gòu)體來描述USB配置,
使用struct usb_device結(jié)構(gòu)體來描述整個USB設(shè)備。
USB設(shè)備的邏輯單元之間的關(guān)系描述如下:
* 設(shè)備通常具有一個或者更多的配置
* 配置經(jīng)常具有一個或者更多的接口
* 接口通常具有一個或者更多的設(shè)置
* 接口沒有或者具有一個以上的端點
-------------------
USB和Sysfs
USB sysfs設(shè)備命名方案為:
根集線器-集線器端口號:配置.接口
如:
2-1:1.0
如果有更多的USB集線器的使用,則設(shè)備名類似于:
根集線器-集線器端口號-集線器端口號:配置.接口
--------------------
USB urb
USB請求塊
通過urb來和所有的USB設(shè)備通信。
這個請求塊使用struct urb結(jié)構(gòu)體來描述 <linux/usb.h>
設(shè)備中的每個端點都可以處理一個urb隊列。
一個urb的典型生命周期:
* 由USB設(shè)備驅(qū)動程序創(chuàng)建
* 分配給一個特定USB設(shè)備的特定端點
* 由USB核心遞交到特定設(shè)備的特定USB主控制器驅(qū)動程序
* 由USB主控制器驅(qū)動程序處理,它從設(shè)備進行USB傳送
* 當urb結(jié)束之后,USB主控制器驅(qū)動程序通知USB設(shè)備驅(qū)動程序。
----------------------
struct urb
struct urb結(jié)構(gòu)體中USB設(shè)備驅(qū)動程序關(guān)心的字段:
struct usb_device *dev
urb所發(fā)送的目標struct usb_device指針。
unsigned int pipe
urb所要發(fā)送的特定目標struct usb_device的端點信息。
有一系列函數(shù)可以用來設(shè)置端點,如usb_sndctrlpipe(),
可以把指定USB設(shè)備的指定端點號設(shè)置為一個控制OUT端點。
unsingned int transfer_flags
該變量可以被設(shè)置為許多不同的位值,
取決于USB驅(qū)動程序?qū)rb的具體操作。
void *transfer_buffer
指向用于發(fā)送數(shù)據(jù)到設(shè)備(OUT urb)或者從設(shè)備接收數(shù)據(jù)(IN urb)
的緩沖區(qū)的指針。
dma_addr_t transfer_dma
用于以DMA方式傳輸數(shù)據(jù)到USB設(shè)備的緩沖區(qū)。
int transfer_buffer_length
transfer_buffer或者transfer_dma變量所指向的緩沖區(qū)的大小。
unsigned char *setup_packet
指向控制urb的設(shè)置數(shù)據(jù)包的指針。
dma_addr_t setup_dma
控制urb用于設(shè)置數(shù)據(jù)包的DMA緩沖區(qū)。
usb_complete_t complete
指向一個結(jié)束處理例程的指針。
void *context
指向一個可以被USB驅(qū)動程序設(shè)置的數(shù)據(jù)塊。
...
-----------------
創(chuàng)建和銷毀urb
struct urb *usb_alloc_urb(int iso_packets,int mem_flags);
void usb_free_urb(struct urb *urb);
----------------
中斷urb
批量urb
控制urb
等時urb
----------------
提交urb
一旦urb被USB驅(qū)動程序正確地創(chuàng)建和初始化之后,
就可以提交到USB核心以發(fā)送到USB設(shè)備了。
這是通過調(diào)用usb_submit_urb函數(shù)來完成的。
int usb_submit_urb(struct urb *urb,int mem_flags);
----------------
結(jié)束urb:結(jié)束回調(diào)處理例程
----------------
取消urb
int usb_kill_urb(struct urb *urb);
int usb_unlink_urb(struct urb *urb);
------------------------------------
編寫USB驅(qū)動程序
驅(qū)動程序把驅(qū)動程序?qū)ο笞缘経SB子系統(tǒng)中,
稍后再使用制造商和設(shè)備標識來判斷是否已經(jīng)安裝了硬件。