當(dāng)前位置:首頁 > 嵌入式 > 嵌入式教程
[導(dǎo)讀]嵌入式Linux下的USB設(shè)備驅(qū)動技術(shù)

Linux以其穩(wěn)定、高效、易定制、硬件支持廣泛、源代碼開放等特點(diǎn),已在嵌入式領(lǐng)域迅速崛起,被國際上許多大型的跨國企業(yè)用作嵌入式產(chǎn)品的系統(tǒng)平臺。

USB是Universal Serial Bus (通用串行總線)的縮寫,是1995年由Microsoft、Compaq、IBM等公司聯(lián)合制定的一種新的PC串行通信協(xié)議。它是一種快速、靈活的總線接口。與其它通信接口相比較,USB接口的最大特點(diǎn)是易于使用,這也是USB的主要設(shè)計(jì)目標(biāo)。USB的成功得益于在USB標(biāo)準(zhǔn)中除定義了通信的物理層和電器層標(biāo)準(zhǔn)外。還定義了一套相對完整的軟件協(xié)議堆棧。這使得多數(shù)USB設(shè)備都很容易在各種平臺上工作。作為一種高速總線接口,USB適用于多種設(shè)備(如數(shù)碼相機(jī)、MP3播放器、高速數(shù)據(jù)采集設(shè)備等)。另外,USB接口還支持熱插拔,而且所有的配置過程都由系統(tǒng)自動完成,無須用戶干預(yù)。

1 Linux下的USB設(shè)備驅(qū)動

在Linux內(nèi)核的不斷升級過程中,驅(qū)動程序的結(jié)構(gòu)相對穩(wěn)定。由于USB設(shè)備也是外圍設(shè)備的一種,因此,它的驅(qū)動程序結(jié)構(gòu)與普通設(shè)備的驅(qū)動程序相同。Linux系統(tǒng)的設(shè)備分為字符設(shè)備(CharDevice)和塊設(shè)備(BlockDevice)。字符設(shè)備支持面向塊字符的I/O操作,它不通過系統(tǒng)的快速緩存,而只支持順序存取。塊設(shè)備則支持面向塊的I/O操作,所有塊設(shè)備的I/O操作都通過在內(nèi)核地址空間的I/O緩沖區(qū)進(jìn)行,可以支持幾乎任意長度和任意位置上的I/O請求。塊設(shè)備與字符設(shè)備還有一點(diǎn)不同,就是塊設(shè)備必須能夠隨機(jī)存取(RandomAccess),字符設(shè)備則沒有這個要求。典型的字符設(shè)備包括鼠標(biāo)、鍵盤、串行口等,而塊設(shè)備主要包括硬盤軟盤設(shè)備、CD-Rom等。由于USB設(shè)備主要都是通過快速串行通訊來讀寫數(shù)據(jù),因此一般都可作為字符設(shè)備來進(jìn)行處理。

2 Linux下的USB core

2.1 Linux中USB core與USB的結(jié)構(gòu)關(guān)系

Linux操作系統(tǒng)中有一個叫做“USB core”的子系統(tǒng),可提供支持USB設(shè)備驅(qū)動程序的API和USB主機(jī)控制器的驅(qū)動程序。同時提供有許多數(shù)據(jù)結(jié)構(gòu)、宏定義和功能函數(shù)來對硬件或設(shè)備進(jìn)行支持。在Linux下編寫USB設(shè)備的驅(qū)動程序時,從嚴(yán)格意義上講,就是使用這些USB core的子系統(tǒng)所定義的數(shù)據(jù)結(jié)構(gòu)、宏和函數(shù)來編寫數(shù)據(jù)的處理功能。在Linux下,core、host controller和driver三者之間的關(guān)系如圖1所示。



2.2 USB core的初始化

USB core從USB子系統(tǒng)的初始化開始。USB子系統(tǒng)的初始化則在文件drivers/usb/core/usb.c里。其代碼如下:

  subsys_initcall(usb_init);
  module_exit(usb_exit);

代碼中的subsys_initcall是一個宏,相當(dāng)于module_init,只不過因?yàn)檫@部分代碼是核心,開發(fā)者通常把它看作一個子系統(tǒng),而不僅僅是一個模塊。因?yàn)閁SB core模塊代表的不是某一個設(shè)備,而是所有USB設(shè)備賴以生存的模塊。因此,在Linux中,像這樣把一個類別的設(shè)備驅(qū)動歸結(jié)為一個子系統(tǒng)(比如PCI子系統(tǒng)、scsi子系統(tǒng)等)?;旧?,drivers/目錄下面第一層的每個目錄都可算作一個子系統(tǒng),因?yàn)樗鼈兇砹艘活愒O(shè)備。一般地,usb_init是真正的初始化函數(shù),而usb_exit()則是整個USB子系統(tǒng)結(jié)束時的清理函數(shù):



函數(shù)usb_init主要完成初始化和注冊設(shè)備。

2.3 USB里的設(shè)備模型

Linux里一個很重要的概念是設(shè)備模型。對于驅(qū)動來說,設(shè)備的概念就是總線和與其相連的各種設(shè)備。在內(nèi)核里,總線、設(shè)備、驅(qū)動也就是bus、device、driver是設(shè)備模型很重要的三個概念,它們都有自己專屬的結(jié)構(gòu)。在include/linux/devide.h里的定義為:

struct bus_type {……};
struct device {……);
struct device_driver {……};

每次出現(xiàn)一個設(shè)備都要向總線注冊,每次出現(xiàn)一個驅(qū)動,也要向總線注冊。系統(tǒng)初始化時,應(yīng)掃描連接許多設(shè)備,并為每一個設(shè)備建立一個struct device的變量。每一次都應(yīng)有一個驅(qū)動程序,并要準(zhǔn)備一個struct device_driver結(jié)構(gòu)的變量。還要把這些變量加入相應(yīng)的鏈表(如把device插入devices鏈表,driver插入drivers鏈表)。這樣,通過總線就能找到每一個設(shè)備和每一個驅(qū)動。然而,假如計(jì)算機(jī)里只有設(shè)備卻沒有對應(yīng)的驅(qū)動,那么設(shè)備將無法工作。反過來,倘若只有驅(qū)動卻沒有設(shè)備,驅(qū)動也起不了任何作用。對于USB設(shè)備,它可以在計(jì)算機(jī)啟動以后再插入或者拔出計(jì)算機(jī)。由于device可以在任何時刻出現(xiàn),而driver也可以在任何時刻被加載,所以,每當(dāng)一個struct device誕生時,它就會去BUS的drivers鏈表中尋找自己的另一半。如果找到了匹配的設(shè)備,就調(diào)用device_bind_driver,并綁定好。

Linux設(shè)備模型中的總線落實(shí)在USB子系統(tǒng)里就是usb_bus_type,它在usb_init函數(shù)中可用retval=bus_register(&usb_bus_type)語句注冊,而在driver.c文件里的定義如下:

[!--empirenews.page--]

該函數(shù)的形參對應(yīng)的就是總線兩條鏈表里的設(shè)備和驅(qū)動。當(dāng)總線上有新設(shè)備和驅(qū)動時,這個函數(shù)就會被調(diào)用。

3 USB驅(qū)動程序的描述符

一個設(shè)備可以有多個接口,一個接口可代表一個功能,因此,每個接口都對應(yīng)著一個驅(qū)動。例如一個USB設(shè)備有兩種功能,一個鍵盤,上面還帶一個揚(yáng)聲器,這就是兩個接口,就需要兩個驅(qū)動程序,一個是鍵盤驅(qū)動程序,一個是音頻流驅(qū)動程序。

一個驅(qū)動程序是否支持一個設(shè)備,要通過讀取設(shè)備的描述符來判斷。那么,什么是USB的描述符呢?USB的描述符是一個帶有預(yù)定義格式的數(shù)據(jù)結(jié)構(gòu),里面保存有USB設(shè)備的各種屬性和相關(guān)信息,可以通過向設(shè)備請求獲得它們的描述符內(nèi)容來深刻了解和感知一個USB設(shè)備。主要有四種USB描述符,分別為:接口描述符、端點(diǎn)描述符、設(shè)備描述符和配置描述符。

協(xié)議規(guī)定:一個USB設(shè)備必須支持這四大描述符,還有些描述符不是必須包含的,有些特殊設(shè)備用來描述設(shè)備的不同特性,但這四大描述符是一個都不能少的。USB設(shè)備里有一個eeprom,可用來存儲設(shè)備本身信息,設(shè)備的描述符就存儲在這里。

上述四個描述符分別放在了include/linux/usb.h文件中的struct usb_host_interface、structusb_host_endpoint、struct usb_device、struetusb_host_config里,而描述符結(jié)構(gòu)體本身定義在include/linux/usb/ch9.h里.并分別用struct usb_interface_descriptor、struct usb_host_endpoint、structusb_device_descriptor和struct usb_config_descriptor來表示。描述符結(jié)構(gòu)體的定義應(yīng)完全按照USB協(xié)議對描述符的規(guī)定來定義。

4 USB接口驅(qū)動

4.1 接口結(jié)構(gòu)

平時編寫的USB驅(qū)動通常指的是寫USB接口的驅(qū)動,一個接口對應(yīng)一個接口驅(qū)動程序,需要以一個struct usb_driver結(jié)構(gòu)的對象為中心,并以設(shè)備的接口提供的功能為基礎(chǔ),來進(jìn)行USB驅(qū)動程序的編寫。struct usb_driver結(jié)構(gòu)體一般定義在include/linux/usb.h文件里。具體如下:

struct usb_driver{
const char*name;
int(*probe)  (struct usb_interface*intf,const
struct usb_device_jd*id);
void(*disconnect)  (struct usb_interface*intf);
int(*ioctl)  (struct usb_interface*intf,unsigned
int code,void*buf);
int  (*suspend)  (struct usb_interface*intf,
pm_message_t message);
int(*resume)  (struct usb_interface*intf);
void(*pre_reset)  (struct usb_interface*intf);
void(*post_reset)(struct usb_interface*intf);
const struct usb_device_id*id_table;
struct usb_dynids dynids;
struct usbdrv_wrap drvwrap;
unsigned int no_dynamic_id:1;
unsigned int supports_autosuspend:1;
};

Name為驅(qū)動程序的名字,對應(yīng)于/sys/bus/usb/drivers/下面的子目錄名稱。它只是彼此區(qū)別的一個代號,這里的名字在所有的USB驅(qū)動中必須是唯一的。probe用來看看這個USB驅(qū)動是否愿意接受某個接口的函數(shù)。Disconnect函數(shù)將在接口失去聯(lián)系或使用rmmod卸載驅(qū)動將它和接口強(qiáng)行分開時被調(diào)用。Ioctl函數(shù)則用在驅(qū)動通過usbfs和用戶空間進(jìn)行交流時使用。Suspend、esume分別在設(shè)備被掛起和喚醒時使用。pre_reset、post_reset分別在設(shè)備將要復(fù)位(reset)和已經(jīng)復(fù)位后使用。id_table的變量可用來判斷是否支持某個設(shè)備接口。Dynids是支持動態(tài)id的。實(shí)際上,即使驅(qū)動已經(jīng)加載了,也可以添加新的id給它。drvwrap是給USB core區(qū)分設(shè)備驅(qū)動和接口驅(qū)動用的。no_dynamic_id可以用來禁止動態(tài)id。supports_autosuspend可對autosuspend提供支持,如果設(shè)置為0,則不再允許綁定到這個驅(qū)動的接口autosuspend。

接口驅(qū)動

當(dāng)insmod或modprobe驅(qū)動的時候,經(jīng)過一個曲折的過程,就會調(diào)用相應(yīng)USB驅(qū)動里的xxx_init函數(shù),進(jìn)而去調(diào)用usb_register (),以將相應(yīng)的USB驅(qū)動提交給設(shè)備模型,添加到USB總線的驅(qū)動鏈表里。當(dāng)rmmod驅(qū)動時,同樣,在經(jīng)過一個曲折的過程之后,再調(diào)用相應(yīng)驅(qū)動里的xxx_cleanup函數(shù),進(jìn)而調(diào)用usb_deregister ()將相應(yīng)的USB驅(qū)動從USB總線的驅(qū)動鏈表里刪除。

5 結(jié)束語

本文介紹了Linux下USB core的工作原理,同時介紹了驅(qū)動USB必須了解的四個描述符。此外,還介紹了Linux下usb接口驅(qū)動的工作原理。本文介紹的方法能適應(yīng)于Linux下各種不同的USB設(shè)備驅(qū)動程序的開發(fā)。

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉