Linux系統下USB驅動程序的設計與開發

論文導讀::操作系統是一個源碼公開、結構清晰、功能強大。總線具有低成本、使用簡單、支持即插即用、易於擴展等特點。本文首先介紹linux驅動程序的架構。

Linux系統下USB驅動程序的設計與開發

關鍵詞:Linux,USB,驅動程序

0引言

Linux操作系統是一個源碼公開、結構清晰、功能強大,且已成爲一個穩定可靠功能完善的系統。其開發羣體的有效組織和高效工作,使得linux系統穩定發展並得到良好維護。

USB總線是Intel、DEC、MicroSoft、IBM等公司聯合提出的一種新的串行總線標準,主要用於PC機與外圍設備的互聯。USB總線具有低成本、使用簡單、支持即插即用、易於擴展等特點,已被廣泛地用在PC機及嵌入式系統上。

在已經研製的家庭網關中,CPU通過自帶的USB接口控制USB設備。本文首先介紹linux驅動程序的架構發表論文,然後介紹USB總線,重點說明USB驅動程序的實現。

x驅動程序基礎

設備驅動程序是操作系統內核和機器硬件之間的接口,爲應用程序屏蔽了硬件的細節。應用程序看待硬件設備只是一個設備文件,應用程序可以象操作普通文件一樣對硬件設備進行操作。設備驅動程序是內核的一部分,它主要完成以下功能:對設備進行初始化,使設備投入運行和退出服務;把數據從內核傳送到設備和從設備接受數據;以及檢測和處理設備出現的錯誤等。

Linux系統的設備一般分爲字符設備、塊設備和網絡設備三種。字符設備是指存取時沒有緩存的設備。塊設備的讀寫都有緩存來支持,並且塊設備必須能夠隨機存取,字符設備則沒有這個要求。一個文件系統要安裝進入操作系統必須在塊設備上。網絡設備在Linux裏做專門的處理。Linux的網絡系統主要是基於BSD unix的socket機制。在系統和驅動程序之間定義有專門的數據結構(sk—buff)進行數據的傳遞。系統裏支持對發送數據和接收數據的緩存,提供流量控制機制,提供對多協議的支持。

系統總線介紹

每一個USB設備會有一個或者多個的邏輯連接點,每個連接點叫端口。每個端口有4種數據傳送方式:控制方式;等時方式;中斷方式和大量方式。但是所有的端口0都是被用來傳送配置和控制信息。

在主機和設備的端口之間的連接叫作管道,與端口0連接的一般稱作爲缺省管道。對於同樣性質的一組端口的組合叫做接口發表論文,如果一個設備包含不止一個的接口就可以稱之爲複合設備。

同理,對於同樣的類型的接口的組合可以稱之爲配置。但是每次只能有一個配置是可用的,而一旦該配置激活,裏面的接口和端口就都同時可以使用。主機從設備發過來的描述符中來判斷用的是哪個配置,哪個接口等等,而這些的描述字通常是在端口0中傳送。

子系統

USB 是一種分層的總線結構,並且是由一個主機(host)來控制。主機用主/副協議來和外部USB設備通訊。USB上的'通訊主要是兩個方向進行的,一個是主機到設備的下行方向, 一個是設備到主機的上行方向,不支持設備間的直接通訊。依靠不同的設備類型,主要有4 種的傳輸方式::控制(control)、中斷(interrupt)、同步(isochronous)、數據塊(bulk);如果是從硬件開始來設計整個的系統,還要正確選擇傳輸的方式。而作爲一個驅動程序的書寫者就只需要弄清楚他是採用的什麼工作方式就行了。通常所有的傳輸方式下的主動權都在 host邊。

在Linux系統中編寫主機部分的USB驅動發表論文,我們不必瞭解太多的硬件知識,因爲Linux 內核模塊中提供了一塊USB內核(USBcore),它給出專門的API來支持USB設備和主控制器。通過定義一系列數據結構,宏命令和函數對所有的硬件和設備支持部分進行抽象。

USB內核包含了所有USB設備驅動和主控制器驅動的共同的USB程序。這些函數主要集中在上層和底層API。如圖1所示,有一個USB設備的驅動的API和一個主控制器的驅動。

圖1USB內核API層

設備驅動框架

USB設備驅動在內核模塊中需要註冊和註銷。因此一個驅動必須註冊2個入口點和一個設備節點。對於特別的USB設備(他們不適合在子系統中註冊)一個驅動可以註冊一對文件操作符和一個次設備號。一般一個驅動可以服務16個相似的USB設備。幾乎所有的USB設備主設備號都是180。

4.1框架數據結構

所有的USB相關的函數和數據結構的名字都是以USB_開頭的。下面給出在子系統中註冊一個USB驅動程序的數據結構。

struct usb _driver {

const char *name; / /模塊的名字

void* ( *probe)(struct usb_device *,unsigned int) ;/ /函數的進入指針

void ( *disconnect) ( struct usb_device *,void * ) ; / /撤銷連接的函數進入指針

struct list_headdriver_list ;/ /給子系統內部使用,初始化時爲 NULL

structfile_operations *fops ;/ /文件操作列表指針

int minor ;/ /次設備號

} ;

這裏特別要提的就是文件操作的結構(structfile_operations),隨着新功能不斷加入 Linux內核,此文件操作的結構也變得越來越大,這種增長是不會有副作用的。因爲對於特定的設備驅動,我們可以選擇自己需要的函數,不需要的就設爲NULL值就可以。下面主要列舉一些USB常用的幾個文件操作函數:

(1)int ( *open) ( struct inode *, struct file*) ; 設備打開操作一般是設備的第一個操作,不過有的設備可以不選擇這個函數。那樣設備的打開操作就會永遠成功發表論文,但系統不會通知你的驅動程序。

(2) void ( *release)( struct inode * , struct file* ) ; 當節點關閉時調用這個操作。

(3) int ( *read) ( struct inode * , struct file * ,char * , int) ; 用來從設備中讀取數據。函數返回一個非負值表示成功的讀取了多時字節。

(4) int ( *write) ( struct inode * , struct file * ,const char * , int ) ; 向設備發數據。如果返回值非負,它就表示成功寫入的字節數。

(5) int ( *select) (struct inode * , struct file * ,int , select_table * ) ; select一般用於程序詢問設備是否可讀或可寫,或是否一個“異常”條件發生了。

(6) int ( *ioctl) ( struct inode * , struct file * ,unsigned int , unsigned long) ; 系統調用 ioctl 提供一種調用設備相關命令的方法。

(7) int ( *mmap) ( struct inode * , struct file* , struct vm_area _struct * ) ; 用來將設備內存映射到進程內存中。

(8) int ( *fsync) ( struct inode * , struct file* ) ; 刷新設備。

4.2框架進入指針

USB 驅動的框架增加了兩個進入指針給普通的設備驅動。

(1) void * probe( struct usb_device * dev , unsigned int interface) ; 當一個新設備加入總線時,這個進入指針就被調用。然後設備驅動將創建一個新的設備數據結構實例。參數dev表示設備的上下文,他包含了所有USB描述符的地址。參數interface表示接口值。如果一個USB驅動想要綁定一個特別的設備或者接口,它必須返回一個指針。這個指針通常指向設備驅動的上下文結構。

(2) voiddisconnect ( struct usb_device * dev ,void * drv_context) ; 這個函數是在設備撤銷連接時調用的。參數dev列出了設備上下文。撤銷連接函數完成後,設備就脫離了USB的框架。以後USB驅動就不能再調用它了。

4.3框架函數

(1)int usb_register ( struct usb_driver * drv) ;這個函數是用來註冊一個新的 USB 設備驅動。指針drv指向結構usb_driver。函數成功返回0。要不然返回一個錯誤值。

(2)voidusb_deregister ( struct usb_driver *drv) ; 此函數是註銷 USB 設備驅動。

(3)voidusb_driver_claim_interface ( struct usb_driver * driver , struct usb_interface *iface ,void * drv_context) ; 此函數是在probe函數執行後,開始爲設備驅動申請更多的接口。Drive指針指向一個完整的已經初始化的usb_driver結構。Iface 指向usb_interface結構,此結構是usb_config_descriptor(可以在usb_device結構中看到)的一部分(在probe函數中賦值)。Drv_context 指針主要指向設備驅動的上下文結構(看probe函數的返回值)。

(4)intusb_interface_claimed (struct usb_inter2face * iface); 這個函數是檢查是否有其他驅動已經聲明瞭這個接口。如果接口沒有被其它驅動申請就返回0。

(5)voidusb_driver_release_interface(structusb_driver * driver , struct usb_interface * iface); 這個函數主要是來釋放先前申請的接口。在 disconnect函數中, , 你不必釋放任何在probe函數中申請的接口。

5.配置USB設備

USB內核API除了包括了一套選擇或詢問的描述符,還有一些配置和更換的設備函數。所有這些標準操作都是通過控制傳輸給設備的。

5.1數據結構的描述

Linux USB子系統通過擴展或內嵌標準的USB描述符來說明描述符的分級結構。這種結構有助於保存指向可選配置和接口的指針。只要被API調用,這些結構的元素就會被描述。關於描述符的詳細信息可以在USB.H查到。

struct usb_device{

. . .

struct usb_config_descriptor* actconfig ;/ * the active configuration * /

. . .

struct usb_device_descriptordescriptor ;/ * Descriptor * /

struct usb_config_descriptor* config ; / * 所有的參數 * }

usb_device 結構是所有USB專門的描述符的根節點。在用驅動配置設備或者請求傳輸的時候發表論文,就必須分解描述符。

5.2標準的設備申請

爲了查詢或者設置一個特殊的配置或可選設置,可以用一個整型函數。並用這個函數建立標準的設備申請(指定設備的控制傳輸)。

(1)intusb_set_configuration (struct usb_device* dev , int configuration); 此函數是激活特殊的配置。0 < =configuration < dev - > descriptor Configurations.

設configuration爲0將設備設爲無地址狀態。這個意思是設備脫離這個設備地址並準備接受一個新的。一般不要設0。因爲你將不能訪問設備,直到被物理的重新連接到總線上。

(2) intusb_set_interface ( struct usb_device *dev , int interface , int alternate) ; 這個函數激活指定接口的可選設置。

(3) intusb_get_device_descriptor ( struct usb_device * dev) ; 這個函數取出了設備完整的描述符結構樹。當一個設備連上總線時,這個函數就會自動被喚醒。或者當一個USB描述符改變時,此函數被調用。

(4) intusb_get_string ( struct usb_device *dev , unsigned short langid , unsigned charindex , void* buf , int size) ; 如果一個設備,配置或者接口描述符涉及到字符串索引值,這個函數可以用來重新獲得字符描述符。標準的USB字符串是以UNICODE編碼的。如果成功就返回0,要不然返回一個錯誤值。

6.結束語

USB的應用越來越廣泛,傳輸速率越來越高。而Linux作爲一種新的操作系統,其發展前景是無法估量的,同時也爲USB總線與各種新型設備互連成爲可能。在Linux下編寫驅動程序的原理和思想與window環境下的驅動程序有很大的區別,在Linux環境下設計驅動程序發表論文,思想簡潔,功能也很強大,但是支持函數少,只能依賴kernel中的函數,有些常用的操作要自己來編寫,而且調試也不方便,還要考慮內核的前後兼容性,因此在設計和實現USB設備時應該注意這些問題。

參考文獻:

[1]毛德操,胡希明x內核源代碼情景分析[M].杭州:浙江大學出版社,2003.

[2]Universal Serial Bus SpecificationRevision[Z]. Compaq, IBM, Intel, Microsoft, NEC, Northern Telecom, 1995.

[3]王偉,王自強,都思丹設備上構建Linux系統的關鍵問題[J].電子測量技術,2008,(06).

[4]沈玉偉,楊永傑,房立鑫.基於μClinux嵌入式網絡打印機服務器[J].計算機時代,2008,(05).

[5]吳麗麗.嵌入式平臺下USB攝像頭驅動的開發與加載[J].科技信息(學術研究),2008,(26).

[6]杜敏傑,馬彥恆,劉利民x下基於CY7C68013芯片的USB設備驅動程序開發[J].科學、技術與工程,2008,(21).

[7]盧志剛,劉建華,劉寶旭,許榕生.基於HID的USB監控技術的設計與實現[J].計算機工程,2010,(04).

[8]宋麗華,高珂.嵌入式Linux下USB攝像頭驅動實現[J].計算機工程,2010,(09).

[9]孫永剛,張學勇,遲歡歡.基於Linux的USB設備驅動的實現[].信息技術,2010,(08).

[10]劉飛,張曦煌.基於嵌入式平臺的USB攝像頭驅動程序的實現[J].計算機工程與設計,2008,(08).

[11]肖珂,歐東梅,郭書軍.嵌入式Linux下高速USB主控制器的設計與實現[J].現代電子技術,2009,(24).

[12]熊春傑x內核移植與USB驅動開發[D].電子科技大學,2007.

[13]程科.嵌入式Linux設備驅動程序的設計與研究[D].電子科技大學,2007.

[14]王強東.面向嵌入式系統的多功能USB設備驅動研究[D].華中科技大學,2007.