關(guān)注自由和開(kāi)源軟件
為什么關(guān)注“自由和開(kāi)源軟件”?使用自由和開(kāi)源軟件 (FOSS)群體的迅速擴(kuò)增,從1980年以來(lái),體現(xiàn)了嵌入式行業(yè)最重要的全面長(zhǎng)期發(fā)展趨勢(shì)。第一,獲得 FOSS軟件許可,就可以使用源代碼,同時(shí)還賦予開(kāi)發(fā)人員研究、變更、改進(jìn)軟件設(shè)計(jì)的權(quán)利。第二,在每一類(lèi)主要軟件的生命周期中,F(xiàn)OSS已經(jīng)或者必將發(fā)揮一定的作用,影響從64位服務(wù)器到8位微控制器的一切平臺(tái)。FOSS將從根本上改變所有用戶(hù)和開(kāi)發(fā)人員對(duì)于軟件價(jià)值主張的看法。因此,大部分嵌入式開(kāi)發(fā)人員或早或晚都會(huì)在設(shè)計(jì)中使用FOSS。
本文引用地址:http://m.butianyuan.cn/article/257884.htm什么是FOSS
“自由軟件”與“開(kāi)源軟件”的主要區(qū)別在于其內(nèi)含的自由概念不同。“自由軟件”許可尊重最終用戶(hù)的幾項(xiàng)基本自由:運(yùn)行軟件的自由;研究和更改軟件的自由;再分發(fā)副本的自由;改進(jìn)程序和發(fā)布這些改進(jìn)的自由可以自由地做這些事情,意味著您不必征求許可或者支付費(fèi)用獲得許可,這是一個(gè)關(guān)于自由的問(wèn)題,而非商業(yè)問(wèn)題,因此應(yīng)理解為“言論自由,而不是免費(fèi)啤酒”。
另外還應(yīng)注意,這些自由是針對(duì)“最終用戶(hù)”而言,而不是開(kāi)發(fā)人員,也不是軟件分發(fā)者。
另一方面,“開(kāi)源軟件”并非始終賦予最終用戶(hù)同樣的自由,但它賦予“開(kāi)發(fā)人員”訪(fǎng)問(wèn)源代碼等權(quán)利。4種開(kāi)源許可都允許開(kāi)發(fā)人員創(chuàng)建專(zhuān)有閉源軟件,而不要求分發(fā)最終成果的源代碼。BSD(伯克利軟件發(fā)行)許可就是其中一例,它允許以二進(jìn)制形式再分發(fā)軟件,無(wú)需提供源代碼。
在現(xiàn)實(shí)世界中,閉源或?qū)S熊浖cFOSS主要區(qū)別在于大眾協(xié)作開(kāi)發(fā)的性質(zhì)不同,前者大家都獨(dú)立開(kāi)發(fā)各自的項(xiàng)目,而后者任何用戶(hù)都可能成為開(kāi)發(fā)人員,報(bào)告并修正缺陷,或者增加新特性。
FOSS受到嵌入式市場(chǎng)歡迎的原因很簡(jiǎn)單,主要是經(jīng)濟(jì)利益驅(qū)動(dòng),它能降低軟件成本,加快產(chǎn)品上市。FOSS將“自主開(kāi)發(fā)”的開(kāi)發(fā)人員變?yōu)橄到y(tǒng)集成者,使其能專(zhuān)注于產(chǎn)品增值和與眾不同的特性,而不是一次次重復(fù)產(chǎn)生相同的基本結(jié)構(gòu)和功能。這是控制軟件開(kāi)發(fā)成本的唯一行之有效的方法。無(wú)論何種組織機(jī)構(gòu),總會(huì)處于采用開(kāi)源軟件五個(gè)階段中的某一階段。
表1:采用FOSS的五個(gè)階段
雖然許多人將FOSS等同于著名的Linux®內(nèi)核或者基于Linux的發(fā)行版,但在嵌入式開(kāi)發(fā)中,超出Linux范圍使用FOSS已經(jīng)非常普遍;幾乎四分之三的組織都在使用它,涉及到成千上萬(wàn)個(gè)項(xiàng)目。然而,隨著基于Linux的嵌入式系統(tǒng)越來(lái)越受歡迎,為嵌入式外設(shè)(ADC、DAC、音頻編解碼器、加速度計(jì)、觸摸屏控制器等)提供Linux驅(qū)動(dòng)程序的需求變得日益迫切。
ADI公司創(chuàng)建、修改和維護(hù)的驅(qū)動(dòng)程序的各層:
•在何處進(jìn)行維護(hù)(驅(qū)動(dòng)程序的下載位置)
•接口代碼(用于內(nèi)核的公共代碼)——允許在您的平臺(tái)上使用驅(qū)動(dòng)程序
•驅(qū)動(dòng)程序開(kāi)發(fā)慣例(哪些文件可以修改或提供,哪些不能)
•何處可以找到代碼——如何提交缺陷和問(wèn)題報(bào)告
Linux設(shè)備驅(qū)動(dòng)程序
多數(shù)Linux用戶(hù)都樂(lè)于不知道Linux內(nèi)核所涉及的底層硬件復(fù)雜性和問(wèn)題,往往會(huì)吃驚地發(fā)現(xiàn)內(nèi)核大部分都與運(yùn)行于其上的硬件無(wú)關(guān)。事實(shí)上,Linux內(nèi)核中的多數(shù)源代碼都與獨(dú)立于架構(gòu)的設(shè)備驅(qū)動(dòng)程序有關(guān):在Linux2.6.32.6內(nèi)核的全部7 934 5669行代碼中,有4 758 810行代碼(60%以上)都位于./drivers,./sound和./firmware目錄下,比例之高令人震驚。與架構(gòu)有關(guān)的代碼只占Linux內(nèi)核的很小一部分,全部22種不同架構(gòu)僅有1 501 545行代碼(18.9%)。Linux內(nèi)核支持的前10大架構(gòu)如表2所示。
表2:Linux內(nèi)核支持的前10大架構(gòu)
這說(shuō)明,與架構(gòu)無(wú)關(guān)約占內(nèi)核源代碼的60%的驅(qū)動(dòng)程序具有舉足輕重的作用。對(duì)于每種支持Linux的硬件,都有人編寫(xiě)過(guò)設(shè)備驅(qū)動(dòng)程序。自2007年以來(lái),ADI公司一直位列為L(zhǎng)inux內(nèi)核10貢獻(xiàn)代碼最多的20家公司之一,并設(shè)立了專(zhuān)職團(tuán)隊(duì)從事Linux設(shè)備驅(qū)動(dòng)程序的開(kāi)發(fā)。
Linux設(shè)備驅(qū)動(dòng)程序的基本知識(shí)
設(shè)備驅(qū)動(dòng)程序用作硬件與使用硬件的應(yīng)用程序(用戶(hù)代碼)或內(nèi)核之間的轉(zhuǎn)譯器,它將硬件的工作細(xì)節(jié)隱藏于幕后,從而起到簡(jiǎn)化編程的作用。編程人員可以利用一套標(biāo)準(zhǔn)化調(diào)用方法(系統(tǒng)調(diào)用)編寫(xiě)高級(jí)應(yīng)用程序代碼,而不必關(guān)心它將控制的特定硬件或運(yùn)行于其上的處理器。借助定義明確的內(nèi)部應(yīng)用程序編程接口(內(nèi)核API),應(yīng)用程序代碼便可以通過(guò)與軟件上層結(jié)構(gòu)或底層硬件無(wú)關(guān)的標(biāo)準(zhǔn)方式與設(shè)備驅(qū)動(dòng)程序?qū)崿F(xiàn)接口。
針對(duì)特定處理器平臺(tái),操作系統(tǒng)(OS)處理硬件操作的細(xì)節(jié)。利用內(nèi)核(OS)內(nèi)部硬件抽象層(HAL)和處理器專(zhuān)用外設(shè)驅(qū)動(dòng)程序(例如I2C®SPI總線(xiàn)驅(qū)動(dòng)程序),通常的設(shè)備驅(qū)動(dòng)程序甚至也能獨(dú)立處理器平臺(tái)。這種方法允許一個(gè)設(shè)備驅(qū)動(dòng)程序(例如觸摸屏數(shù)字化儀AD7879的驅(qū)動(dòng)程序)可以不加修改地用在任何運(yùn)行Linux的處理器平臺(tái)上,Linux內(nèi)核之上運(yùn)行任何圖形用戶(hù)界面(GUI)包和適當(dāng)?shù)膽?yīng)用程序。如果硬件設(shè)計(jì)人員決定轉(zhuǎn)而使用觸摸屏控制器AD7877,他(她)將無(wú)需軟件團(tuán)隊(duì)提供信息。兩款器件均可用驅(qū)動(dòng)程序;雖然器件不同,連接方式可能不同(AD7877僅提供SPI,AD7879則有SPI或I2C),并且寄存器圖也不相同,但相對(duì)于觸摸屏用戶(hù)代碼的內(nèi)核API完全相同。這樣,對(duì)硬件的控制權(quán)便又回到硬件架構(gòu)師手中。
Linux內(nèi)核中的不同類(lèi)型設(shè)備驅(qū)動(dòng)程序提供不同的抽象層次,傳統(tǒng)上一般將其分為以下三類(lèi)。
字符設(shè)備:處理字節(jié)流。串行端口或輸入設(shè)備驅(qū)動(dòng)程序(鍵盤(pán)、鼠標(biāo)、觸摸屏、游戲操縱桿等)通常實(shí)現(xiàn)字符設(shè)備類(lèi)型。
塊數(shù)據(jù)設(shè)備:?jiǎn)未尾僮魈幚?12字節(jié)或更多的二次冪塊數(shù)據(jù)。存儲(chǔ)設(shè)備驅(qū)動(dòng)程序通常實(shí)現(xiàn)此類(lèi)塊設(shè)備。
網(wǎng)絡(luò)接口:任何網(wǎng)絡(luò)事務(wù)都通過(guò)接口完成,接口指能夠與其他主機(jī)交換數(shù)據(jù)的設(shè)備。
在Linux內(nèi)核中,各特殊類(lèi)別都可能有多個(gè)獨(dú)立的設(shè)備核心層,以幫助開(kāi)發(fā)人員實(shí)現(xiàn)提供標(biāo)準(zhǔn)用途的驅(qū)動(dòng)程序,如視頻、音頻、網(wǎng)絡(luò)、輸入設(shè)備或背光處理等。通常,每個(gè)子系統(tǒng)在Linux內(nèi)核源代碼樹(shù)中都有其自己的目錄。這種“設(shè)備驅(qū)動(dòng)程序核心方法”消除了特定類(lèi)別所有設(shè)備驅(qū)動(dòng)程序的公共代碼,為上層構(gòu)建了一個(gè)標(biāo)準(zhǔn)接口。每類(lèi)設(shè)備或總線(xiàn)設(shè)備核心驅(qū)動(dòng)程序通常會(huì)將一個(gè)函數(shù)集導(dǎo)出至其子類(lèi)。驅(qū)動(dòng)程序利用這種核心驅(qū)動(dòng)程序注冊(cè),并使用核心驅(qū)動(dòng)程序所導(dǎo)出的API,而不是注冊(cè)其自己的字符/塊/網(wǎng)絡(luò)驅(qū)動(dòng)程序。這通常包括支持和處理多個(gè)實(shí)例以及在層間分配數(shù)據(jù)的方式。絕大部分系統(tǒng)無(wú)意了解設(shè)備如何連接,但需要知道何種設(shè)備可用。Linux設(shè)備模型也包括一種將設(shè)備指派給特定類(lèi)別的機(jī)制,如input(輸入)、RTC(實(shí)時(shí)時(shí)鐘)、net(網(wǎng)絡(luò))或GPIO(通用輸入/輸出)等。這些類(lèi)名在更高的功能層次描述設(shè)備,使之能在用戶(hù)空間中被發(fā)現(xiàn)。
特定硬件可能有多個(gè)設(shè)備驅(qū)動(dòng)程序子系統(tǒng)與之相關(guān)。多功能芯片,例如帶I/O擴(kuò)展器的背光驅(qū)動(dòng)器ADP5520,會(huì)同時(shí)利用Linux背光、LED、GPIO和輸入子系統(tǒng)來(lái)實(shí)現(xiàn)其鍵盤(pán)功能。
如前文所述,用戶(hù)應(yīng)用程序不能直接與硬件通信,因?yàn)槟菍⒁髶碛袑?duì)處理器的管理員權(quán)限,例如執(zhí)行特殊指令或處理中斷。使用特定硬件設(shè)備的應(yīng)用程序通常在通過(guò)/dev目錄中的節(jié)點(diǎn)暴露的內(nèi)核驅(qū)動(dòng)程序上工作。
設(shè)備節(jié)點(diǎn)稱(chēng)為偽文件,因?yàn)樗鼈兛雌饋?lái)像文件;應(yīng)用程序也可以打開(kāi)或關(guān)閉它們(open()或close()),但在讀取或?qū)懭脒@些文件時(shí),數(shù)據(jù)來(lái)自或傳遞至設(shè)備節(jié)點(diǎn)相關(guān)的驅(qū)動(dòng)程序。這個(gè)抽象層次由Linux內(nèi)核中的虛擬文件系統(tǒng)(VFS)處理。除了read()、write()或poll()外,用戶(hù)應(yīng)用程序也可以利用ioctl()(輸入/輸出控制)與設(shè)備交互。
除設(shè)備節(jié)點(diǎn)外,應(yīng)用程序也可以利用/sys目錄中的文件條目;這是一個(gè)sysfs虛擬文件系統(tǒng),可將有關(guān)設(shè)備和驅(qū)動(dòng)程序的信息,包括父子關(guān)系或與特定類(lèi)、總線(xiàn)的關(guān)聯(lián),從內(nèi)核設(shè)備模型導(dǎo)出至用戶(hù)空間。/sys也頻繁用于設(shè)備配置,特別是當(dāng)相關(guān)驅(qū)動(dòng)程序以一個(gè)設(shè)備驅(qū)動(dòng)程序核心注冊(cè)時(shí),此時(shí)它只將其標(biāo)準(zhǔn)功能集導(dǎo)出給用戶(hù)。
設(shè)備驅(qū)動(dòng)程序可以注冊(cè)/sys“鉤子”或“條目”;讀取或?qū)懭脬^子或條目時(shí),將執(zhí)行設(shè)備驅(qū)動(dòng)程序?qū)iT(mén)注冊(cè)的回調(diào)函數(shù)。這些回調(diào)函數(shù)(在管理員模式下運(yùn)行)可以接受參數(shù)、發(fā)起總線(xiàn)傳輸、調(diào)用某種處理、修改特定設(shè)備變量,并將整數(shù)值或字符串返回給用戶(hù)。這就為實(shí)現(xiàn)其他功能創(chuàng)造了條件;例如,用戶(hù)空間可以使用觸摸屏數(shù)字化儀AD7877的溫度傳感器或輔助ADC。
設(shè)備驅(qū)動(dòng)程序既可以靜態(tài)地構(gòu)建于內(nèi)核中,也可以在以后作為可加載模塊動(dòng)態(tài)安裝。Linux內(nèi)核模塊(LKM)是動(dòng)態(tài)組件,可以在運(yùn)行時(shí)插入和移除。這對(duì)于驅(qū)動(dòng)程序開(kāi)發(fā)人員特別有用,因?yàn)楦斓木幾g速度可以節(jié)省時(shí)間,而且測(cè)試模塊不必重啟系統(tǒng)。讓硬件驅(qū)動(dòng)程序駐留在可以隨時(shí)載入內(nèi)核的模塊中,便可以在特定硬件不用時(shí)節(jié)約RAM。
加載模塊時(shí),也可以賦予其配置參數(shù)。對(duì)于構(gòu)建于內(nèi)核中的模塊,參數(shù)在內(nèi)核啟動(dòng)時(shí)傳送給該模塊。例如:
root:~> insmod ./sample_module.ko argument=1
root:~> lsmod
Module Size Used by
sample_module 1396 0 - Live 0x00653000
root:~> rmmod sample_module
驅(qū)動(dòng)程序也可以多次實(shí)例化,每次實(shí)例化都可以采用不同的設(shè)置,目標(biāo)設(shè)備可以有不同的I2C從ID,連接到不同的SPI從選擇,或者映射到不同的物理存儲(chǔ)器地址。所有實(shí)例共用同樣的代碼,以便節(jié)省存儲(chǔ)器,但具有各自的數(shù)據(jù)段。
Linux是一種先占式多任務(wù)、多用戶(hù)操作系統(tǒng),因此幾乎所有設(shè)備驅(qū)動(dòng)程序和內(nèi)核子系統(tǒng)都允許多個(gè)進(jìn)程(可能由不同的用戶(hù)所有)同時(shí)利用設(shè)備。常見(jiàn)的例子有network(網(wǎng)絡(luò))、audio(音頻)或input(輸入)接口。QWERTY鍵盤(pán)控制器ADP5588的鍵按下或釋放事件會(huì)被加上時(shí)間戳、排隊(duì)并發(fā)送至所有已打開(kāi)input vent device(輸入事件設(shè)備)的進(jìn)程。這些事件代碼在所有架構(gòu)上都相同,并且與硬件無(wú)關(guān)。讀USB鍵盤(pán)與從用戶(hù)空間讀取ADP5588并無(wú)區(qū)別。事件類(lèi)型通過(guò)代碼加以區(qū)分。鍵盤(pán)發(fā)送鍵事件(EV_KEY)、鍵識(shí)別碼以及代表按下或釋放動(dòng)作的某種狀態(tài)值。觸摸屏發(fā)送絕對(duì)坐標(biāo)事件(EV_ABS)以及由x、y和觸摸壓力組成的一個(gè)三元組,鼠標(biāo)則發(fā)送相對(duì)運(yùn)動(dòng)事件(EV_REL)。加速度計(jì)ADXL346在發(fā)送關(guān)于加速度的絕對(duì)坐標(biāo)事件的同時(shí),可以發(fā)送關(guān)于單振或雙振的鍵事件。
某些應(yīng)用中,加速度計(jì)ADXL346產(chǎn)生相對(duì)事件或者發(fā)送特定鍵代碼(特定應(yīng)用設(shè)置),也很有意義。一般而言,定制驅(qū)動(dòng)程序有兩種方式:運(yùn)行時(shí)或編譯時(shí)。
可能在運(yùn)行時(shí)進(jìn)行定制的設(shè)備特性使用模塊參數(shù)和或/sys條目。
實(shí)現(xiàn)特定目標(biāo)
使用開(kāi)源Linux驅(qū)動(dòng)程序—通過(guò)定制實(shí)現(xiàn)特定目標(biāo),對(duì)于編譯時(shí)配置,將特定板和特定應(yīng)用配置排除在主驅(qū)動(dòng)程序文件之外是Linux的慣例,一般將其放入board support ?le(板支持文件)中。
對(duì)于定制板上的設(shè)備(這是嵌入式和基于SoC片上系統(tǒng)硬件的典型現(xiàn)象),Linux使用platform_data指向描述設(shè)備及其如何連到SoC的特定板結(jié)構(gòu)。這可以包括可用端口、不同芯片版本、首選模式、默認(rèn)初始化、引腳的其他作用等。這將能縮小板支持包(BSP),并盡量減少驅(qū)動(dòng)程序中板和應(yīng)用特定的#ifdef。至于哪些可調(diào)變量進(jìn)入platform_data,哪些應(yīng)當(dāng)在運(yùn)行時(shí)具有訪(fǎng)問(wèn)權(quán),則由驅(qū)動(dòng)程序的作者決定。
數(shù)字加速度計(jì)特性與應(yīng)用具有非常密切的關(guān)系,不同的板和型號(hào)可能具有不同的特性。下例顯示了一組配置選項(xiàng)。這些變量在頭文件adxl34x.h(include/linux/input/adxl34x.h)中有詳細(xì)描述。
Analog Dialogue 44-03, March (2010)
#include linux/input/adxl34x.h>
static const struct adxl34x_platform_data
adxl34x_info={
.x_axis_offset=0,
.y_axis_offset=0,
.z_axis_offset=0,
.tap_threshold=0x31,
.tap_duration=0x10,
.tap_latency=0x60,
.tap_window=0xF0,
.tap_axis_control=ADXL_TAP_X_EN | ADXL_TAP_
Y_EN | ADXL_TAP_Z_EN,
.act_axis_control=0xFF,
.activity_threshold=5,
.inactivity_threshold=3,
.inactivity_time=4,
.free_fall_threshold=0x7,
.free_fall_time=0x20,
.data_rate=0x8,
.data_range=ADXL_FULL_RES,
.ev_type=EV_ABS,
.ev_code_x=ABS_X,/*EV_REL*/
.ev_code_y=ABS_Y,/*EV_REL*/
.ev_code_z=ABS_Z,/*EV_REL*/
.ev_code_tap={BTN_TOUCH,BTN_TOUCH,BTN_TOUCH},/*EV_KEY x,y,z */
.ev_code_ff=KEY_F,/* EV_KEY */
.ev_code_act_inactivity=KEY_A,/*EV_KEY*/
.power_mode=ADXL_AUTO_SLEEP|ADXL_LINK,
.fifo_mode=ADXL_FIFO_STREAM,
};
為將設(shè)備與驅(qū)動(dòng)程序相關(guān)聯(lián),“平臺(tái)和總線(xiàn)模型”無(wú)需設(shè)備驅(qū)動(dòng)程序來(lái)包含其所控制設(shè)備的硬編碼物理地址或總線(xiàn)ID。平臺(tái)和總線(xiàn)模型還能防止資源沖突,大大改善便攜性,并與內(nèi)核的電源管理特性干凈利落地接口。
利用平臺(tái)和總線(xiàn)模型,設(shè)備驅(qū)動(dòng)程序一旦獲得設(shè)備的物理位置和中斷線(xiàn)路,便知道如何控制設(shè)備。該信息在探測(cè)期間作為一個(gè)數(shù)據(jù)結(jié)構(gòu)傳遞給驅(qū)動(dòng)程序。
與PCI或USB設(shè)備不同,I2C或SPI設(shè)備不會(huì)在硬件層次上進(jìn)行枚舉。相反,軟件必須知道每個(gè)I2C/SPI總線(xiàn)段上連接了哪些設(shè)備,以及這些設(shè)備使用什么地址。因此,內(nèi)核代碼必須明確實(shí)例化I2C/SPI設(shè)備。這可以通過(guò)多種不同方法實(shí)現(xiàn),具體取決于上下文和要求。不過(guò),最常用的方法是通過(guò)總線(xiàn)號(hào)碼聲明I2C/SPI設(shè)備。
當(dāng)I2C/SPI總線(xiàn)是一條系統(tǒng)總線(xiàn)時(shí),這種方法是合適的;許多嵌入式系統(tǒng)正是這種情況,其中每條I2C/SPI總線(xiàn)都有一個(gè)事先已知的號(hào)碼。因此,可以預(yù)先聲明連到該總線(xiàn)的I2C/SPI設(shè)備。這可以利用一個(gè)結(jié)構(gòu)體i2c_board_info/spi_board_info陣列來(lái)完成,該陣列通過(guò)調(diào)用以下內(nèi)容注冊(cè)i2c_register_board_info()/spi_register_board_info()
static struct i2c_board_info __initdata bfin_ i2c_board_info[] = {#if defined(CONFIG_TOUCHSCREEN_AD7879_I2C)||defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
{
I2C_BOARD_INFO(ad7879,0x2F),
.irq=IRQ_PG5,
.platform_data=(void*)bfin_ad7879_ts_info,
},
#endif
#ifdefined(CONFIG_KEYBOARD_ADP5588)||defined(CONFIG_KEYBOARD_ADP5588_MODULE)
{
I2C_BOARD_INFO(adp5588-keys,0x34),
.irq=IRQ_PG0,
.platform_data=(void*)adp5588_kpad_data,
},
#endif
#ifdefined(CONFIG_PMIC_ADP5520)||defined(CONFIG_PMIC_ADP5520_MODULE)
{
I2C_BOARD_INFO(pmic-adp5520,0x32),
.irq=IRQ_PG0,
.platform_data=(void*)adp5520_pdev_data,
},
#endif
#ifefined(CONFIG_INPUT_ADXL34X_I2C)|| defined(CONFIG_INPUT_ADXL34X_I2C_MODULE)
{
I2C_BOARD_INFO(adxl34x, 0x53),
.irq = IRQ_PG0,
.platform_data = (void *)adxl34x_info,
},
#endif
};
static void __init blackfin_init(void)
{
(...)
i2c_register_board_info(0,bfin_i2c_board_info, ARRAY_SIZE(bfin_i2c_board_info));
spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
(...)
}
因此,為了啟用這樣一個(gè)驅(qū)動(dòng)程序,只需要編輯板支持文件,將適當(dāng)?shù)臈l目添加至i2c_board_info(spi_board_info)。
還應(yīng)注意到,需在內(nèi)核配置期間選擇驅(qū)動(dòng)程序。驅(qū)動(dòng)程序按照所屬的子系統(tǒng)分類(lèi)。可在以下位置查找ADXL34x驅(qū)動(dòng)程序:
Device Drivers--->
Input device support --->
[*] Miscellaneous devices --->
M>Analog Devices AD714x Capacitance Touch Sensor
M>support I2C bus connection
M>support SPI bus connection
*>Analog Devices ADXL34x Three-Axis
Digital Accelerometer
*>support I2C bus connection
*>support SPI bus connection
一旦用戶(hù)開(kāi)始內(nèi)核構(gòu)建過(guò)程,就會(huì)自動(dòng)編譯所選的驅(qū)動(dòng)程序。上面的代碼聲明I2C總線(xiàn)0上有四個(gè)設(shè)備,包括其各自的地址、IRQ以及其驅(qū)動(dòng)程序所需的定制platform_data。注冊(cè)相關(guān)I2C總線(xiàn)時(shí),i2c-core內(nèi)核子系統(tǒng)會(huì)自動(dòng)實(shí)例化這些I2C設(shè)備。
static struct i2c_driver adxl34x_driver = {
.driver={
.name=adxl34x,
.owner=THIS_MODULE,
},
.probe=adxl34x_i2c_probe,
.remove=__devexit_p(adxl34x_i2c_remove),
.suspend=adxl34x_suspend,
.resume=adxl34x_resume,
.id_table=adxl34x_id,
};
static int __init adxl34x_i2c_init(void)
{
return i2c_add_driver(adxl34x_driver);
}
module_init(adxl34x_i2c_init);
在內(nèi)核啟動(dòng)的某一時(shí)間點(diǎn),或者在其后的任何時(shí)候,一個(gè)名為adxl34x的設(shè)備驅(qū)動(dòng)程序可以利用struct i2c_driver注冊(cè)自己——通過(guò)調(diào)用i2c_add_driver()進(jìn)行注冊(cè)。struct i2c_driver的成員利用指向ADXL34x驅(qū)動(dòng)程序函數(shù)的指針進(jìn)行設(shè)置,將驅(qū)動(dòng)程序與其總線(xiàn)主控內(nèi)核相連接。(宏module_init()定義模塊插入時(shí)調(diào)用哪個(gè)函數(shù)(adxl34x_ i2c_init())。)
如果存檔的驅(qū)動(dòng)程序名稱(chēng)與宏I2C_BOARD_INFO所提供的名稱(chēng)相符,i2c-core總線(xiàn)模型實(shí)現(xiàn)方法將調(diào)用驅(qū)動(dòng)程序的probe()函數(shù),將相關(guān)的platform_data和irq從板支持文件傳遞到驅(qū)動(dòng)程序。這僅會(huì)在沒(méi)有追索沖突的情況下發(fā)生,例如前一實(shí)例化設(shè)備使用同一I2C從地址時(shí)。
adxl34x_i2c_probe()函數(shù)隨后開(kāi)始執(zhí)行其名稱(chēng)所表示的功能。它通過(guò)讀取制造商和設(shè)備ID,檢查ADXL345或ADXL346是否存在以及是否正常工作。如果檢查成功,驅(qū)動(dòng)程序的探測(cè)函數(shù)將分配特定設(shè)備數(shù)據(jù)結(jié)構(gòu),請(qǐng)求中斷,并初始化加速度計(jì)。
然后利用input_allocate_device()分配新的輸入設(shè)備結(jié)構(gòu),并設(shè)置輸入位域。這樣,設(shè)備驅(qū)動(dòng)程序就告知輸入系統(tǒng)的其他部分這是何種設(shè)備,以及這種新的輸入設(shè)備能夠產(chǎn)生何種事件。最后,ADXL34x驅(qū)動(dòng)程序通過(guò)調(diào)用input_register_device()注冊(cè)該輸入設(shè)備。
這將把新的輸入設(shè)備結(jié)構(gòu)添加到輸入驅(qū)動(dòng)程序的鏈接列表中,并調(diào)用設(shè)備處理程序模塊的連接函數(shù),告知其已出現(xiàn)一個(gè)新的輸入設(shè)備。從此時(shí)起,該設(shè)備可以產(chǎn)生中斷。一旦執(zhí)行中斷服務(wù)例程,就會(huì)從加速度計(jì)讀取狀態(tài)寄存器和事件FIFO,并利用nput_event()向輸入子系統(tǒng)發(fā)回適當(dāng)?shù)氖录?/p>
linux操作系統(tǒng)文章專(zhuān)題:linux操作系統(tǒng)詳解(linux不再難懂)linux相關(guān)文章:linux教程
評(píng)論