Linux驅(qū)動基礎(chǔ)開發(fā)入門.doc_第1頁
Linux驅(qū)動基礎(chǔ)開發(fā)入門.doc_第2頁
Linux驅(qū)動基礎(chǔ)開發(fā)入門.doc_第3頁
Linux驅(qū)動基礎(chǔ)開發(fā)入門.doc_第4頁
Linux驅(qū)動基礎(chǔ)開發(fā)入門.doc_第5頁
已閱讀5頁,還剩18頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

目前,Linux軟件工程師大致可分為兩個層次:-(1)Linux應(yīng)用軟件工程師(Application Software Engineer): 主要利用C庫函數(shù)和Linux API進(jìn)行應(yīng)用軟件的編寫; 從事這方面的開發(fā)工作,主要需要學(xué)習(xí):符合linux posix標(biāo)準(zhǔn)的API函數(shù)及系統(tǒng)調(diào)用,linux的多任務(wù)編程技巧:多進(jìn)程、多線程、進(jìn)程間通信、多任務(wù)之間的同步互斥等,嵌入式數(shù)據(jù)庫的學(xué)習(xí),UI編程:QT、miniGUI等。(2)Linux固件工程師(Firmware Engineer): 主要進(jìn)行Bootloader、Linux的移植及Linux設(shè)備驅(qū)動程序的設(shè)計工作。一般而言,固件工程師的要求要高于應(yīng)用軟件工程師的層次,而其中的Linux設(shè)備驅(qū)動編程又是Linux程序設(shè)計中比較復(fù)雜的部分,究其原因,主要包括如下幾個方面: 1)設(shè)備驅(qū)動屬于Linux內(nèi)核的部分,編寫Linux設(shè)備驅(qū)動需要有一定的Linux操作系統(tǒng)內(nèi)核基礎(chǔ);需要了解部分linux內(nèi)核的工作機(jī)制與系統(tǒng)組成 2)編寫Linux設(shè)備驅(qū)動需要對硬件的原理有相當(dāng)?shù)牧私猓蠖鄶?shù)情況下我們是針對一個特定的嵌入式硬件平臺編寫驅(qū)動的,例如:針對特定的主機(jī)平臺:可能是三星的2410、2440,也可能是atmel的,或者飛思卡爾的等等 3)Linux設(shè)備驅(qū)動中廣泛涉及到多進(jìn)程并發(fā)的同步、互斥等控制,容易出現(xiàn)bug;因?yàn)閘inux本身是一個多任務(wù)的工作環(huán)境,不可避免的會出現(xiàn)在同一時刻對同一設(shè)備發(fā)生并發(fā)操作 4)由于屬于內(nèi)核的一部分,Linux設(shè)備驅(qū)動的調(diào)試也相當(dāng)復(fù)雜。linux設(shè)備驅(qū)動沒有一個很好的IDE環(huán)境進(jìn)行單步、變量查看等調(diào)試輔助工具;linux驅(qū)動跟linux內(nèi)核工作在同一層次,一旦發(fā)生問題,很容易造成內(nèi)核的整體崩潰。 本系列文章我們將一步步、深入淺出的介紹linux設(shè)備驅(qū)動編程中設(shè)計的一些問題及學(xué)習(xí)方法,希望對大家學(xué)習(xí)linux設(shè)備驅(qū)動有所幫助。 在任何一個計算機(jī)系統(tǒng)中,大至服務(wù)器、PC機(jī)、小至手機(jī)、mp3/mp4播放器,無論是復(fù)雜的大型服務(wù)器系統(tǒng)還是一個簡單的流水燈單片機(jī)系統(tǒng),都離不開驅(qū)動程序的身影,沒有硬件的軟件是空中樓閣,沒有軟件的硬件只是一堆廢鐵,硬件是底層的基礎(chǔ),是所有軟件得以運(yùn)行的平臺,代碼最終會落實(shí)到硬件上的邏輯組合。 但是硬件與軟件之間存在一個駁論:為了快速、優(yōu)質(zhì)的完成軟件功能設(shè)計,應(yīng)用程序工程師不想也不愿關(guān)心硬件,而硬件工程師也很難有功夫去處理軟件開發(fā)中的一些應(yīng)用。例如軟件工程師在調(diào)用printf的時候,不許也不用關(guān)心信息到底是通過什么樣的處理,走過哪些通路顯示在該顯示的地方,硬件工程師在寫完了一個4*4鍵盤驅(qū)動后,無需也不必管應(yīng)用程序在獲得鍵值后做哪些處理及操作。 也就是說軟件工程師需要看到一個沒有硬件的純軟件世界,硬件必須透明的提供給他,誰來實(shí)現(xiàn)這一任務(wù)?答案是驅(qū)動程序,驅(qū)動程序從字面解釋就是:“驅(qū)使硬件設(shè)備行動”。驅(qū)動程序直接與硬件打交道,按照硬件設(shè)備的具體形式,驅(qū)動設(shè)備的寄存器,完成設(shè)備的輪詢、中斷處理、DMA通信,最終讓通信設(shè)備可以收發(fā)數(shù)據(jù),讓顯示設(shè)備能夠顯示文字和畫面,讓音頻設(shè)備可以完成聲音的存儲和播放。 可見,設(shè)備驅(qū)動程序充當(dāng)了硬件和軟件之間的樞紐,因此驅(qū)動程序的表現(xiàn)形式可能就是一些標(biāo)準(zhǔn)的、事先協(xié)定好的API函數(shù),驅(qū)動工程師只需要去完成相應(yīng)函數(shù)的填充,應(yīng)用工程師只需要調(diào)用相應(yīng)的接口完成相應(yīng)的功能。無論有沒有操作系統(tǒng),驅(qū)動程序都有其存在價值,只是在裸機(jī)情況下,工作環(huán)境比較簡單、完成的工作較單一,驅(qū)動程序完成的功能也就比較簡單,同時接口只要在小范圍內(nèi)符合統(tǒng)一的標(biāo)準(zhǔn)即可。但是在有操作系統(tǒng)的情況下,此問題就會被放大:硬件來自不同的公司、千變?nèi)f化,全世界每天都會有大量的新芯片被生產(chǎn),大量的電路板被設(shè)計出來,如果沒有一個很好的統(tǒng)一標(biāo)準(zhǔn)去規(guī)范這一程序,操作系統(tǒng)就會被設(shè)計的非常冗余,效率會非常低。 所以無論任何操作系統(tǒng)都會制定一套標(biāo)準(zhǔn)的架構(gòu)去管理這些驅(qū)動程序:linux作為嵌入式操作系統(tǒng)的典范,其驅(qū)動架構(gòu)具有很高的規(guī)范性與聚合性,不但把不同的硬件設(shè)備分門別類、綜合管理,并且針對不同硬件的共性進(jìn)行了統(tǒng)一抽象,將其硬件相關(guān)性降到最低,大大簡化了驅(qū)動程序的編寫,形成了具有其特色的驅(qū)動組織架構(gòu)。下圖反映了應(yīng)用程序、linux內(nèi)核、驅(qū)動程序、硬件的關(guān)系。linux內(nèi)核分為5大部分:多任務(wù)管理、內(nèi)存管理、文件系統(tǒng)管理、設(shè)備管理、網(wǎng)絡(luò)管理;每一部分都有承上下的作用,對上提供API接口,提供給應(yīng)用開發(fā)工程師使用;對下通過驅(qū)動程序屏蔽不同的硬件構(gòu)成,完成硬件的具體操作。、學(xué)習(xí)linux設(shè)備驅(qū)動首先我們必須明確以下幾個概念,為我們接下來學(xué)習(xí)linux驅(qū)動打下堅實(shí)的基礎(chǔ):應(yīng)用程序、庫、內(nèi)核、驅(qū)動程序的關(guān)系設(shè)備類型設(shè)備文件、主設(shè)備號與從設(shè)備號驅(qū)動程序與應(yīng)用程序的區(qū)別用戶態(tài)與內(nèi)核態(tài)Linux驅(qū)動程序功能一、應(yīng)用程序、庫、內(nèi)核、驅(qū)動程序的關(guān)系 1)應(yīng)用程序調(diào)用一系列函數(shù)庫,通過對文件的操作完成一系列功能: 應(yīng)用程序以文件形式訪問各種硬件設(shè)備(linux特有的抽象方式,把所有的硬件訪問抽象為對文件的讀寫、設(shè)置) 函數(shù)庫: 部分函數(shù)無需內(nèi)核的支持,由庫函數(shù)內(nèi)部通過代碼實(shí)現(xiàn),直接完成功能 部分函數(shù)涉及到硬件操作或內(nèi)核的支持,由內(nèi)核完成對應(yīng)功能,我們稱其為系統(tǒng)調(diào)用 2)內(nèi)核處理系統(tǒng)調(diào)用,根據(jù)設(shè)備文件類型、主設(shè)備號、從設(shè)備號(后面會講解),調(diào)用設(shè)備驅(qū)動程序; 3)設(shè)備驅(qū)動直接與硬件通信;資源把數(shù)據(jù)從內(nèi)核傳送到硬件和從硬件讀取數(shù)據(jù)讀取應(yīng)用程序傳送給設(shè)備文件的數(shù)據(jù)和回送應(yīng)用程序請求的數(shù)據(jù)檢測和處理設(shè)備出現(xiàn)的錯誤(底層協(xié)議)用于區(qū)分具體設(shè)備的實(shí)例二、設(shè)備類型 硬件是千變?nèi)f化的,沒有八千也有一萬了,就像世界上有三種人:男人、女人、女博士一樣,linux做了一個很偉大也很艱難的分類:把所有的硬件設(shè)備分為三大類:字符設(shè)備、塊設(shè)備、網(wǎng)絡(luò)設(shè)備。1)字符設(shè)備:字符(char)設(shè)備是個能夠像字節(jié)流(類似文件)一樣被訪問的設(shè)備。 對字符設(shè)備發(fā)出讀/寫請求時,實(shí)際的硬件I/O操作一般緊接著發(fā)生; 字符設(shè)備驅(qū)動程序通常至少要實(shí)現(xiàn)open、close、read和write系統(tǒng)調(diào)用。 比如我們常見的lcd、觸摸屏、鍵盤、led、串口等等,就像男人是用來干活的一樣,他們一般對應(yīng)具體的硬件都是進(jìn)行出具的采集、處理、傳輸。2)塊設(shè)備:一個塊設(shè)備驅(qū)動程序主要通過傳輸固定大小的數(shù)據(jù)(一般為512或1k)來訪問設(shè)備。 塊設(shè)備通過buffer cache(內(nèi)存緩沖區(qū))訪問,可以隨機(jī)存取,即:任何塊都可以讀寫,不必考慮它在設(shè)備的什么地方。 塊設(shè)備可以通過它們的設(shè)備特殊文件訪問,但是更常見的是通過文件系統(tǒng)進(jìn)行訪問。 只有一個塊設(shè)備可以支持一個安裝的文件系統(tǒng)。 比如我們常見的電腦硬盤、SD卡、U盤、光盤等,就像女人一樣是用來存儲信息的。3)網(wǎng)絡(luò)接口:任何網(wǎng)絡(luò)事務(wù)都經(jīng)過一個網(wǎng)絡(luò)接口形成,即一個能夠和其他主機(jī)交換數(shù)據(jù)的設(shè)備。 訪問網(wǎng)絡(luò)接口的方法仍然是給它們分配一個唯一的名字(比如eth0),但這個名字在文件系統(tǒng)中不存在對應(yīng)的節(jié)點(diǎn)。 內(nèi)核和網(wǎng)絡(luò)設(shè)備驅(qū)動程序間的通信,完全不同于內(nèi)核和字符以及塊驅(qū)動程序之間的通信,內(nèi)核調(diào)用一套和數(shù)據(jù)包傳輸相關(guān)的函數(shù)(socket函數(shù))而不是read、write等。 比如我們常見的網(wǎng)卡設(shè)備、藍(lán)牙設(shè)備,就像女博士一樣,數(shù)量稀少但又不可或缺。 linux中所有的驅(qū)動程序最終都能歸到這三種設(shè)備中,當(dāng)然他們之間也沒有非常嚴(yán)格的界限,這些都是程序中對他們的劃分而已,比如一個sd卡,我們也可以把它封裝成字符設(shè)備去操作也是沒有問題的。就像。三、設(shè)備文件、主設(shè)備號、從設(shè)備號有了設(shè)備類型的劃分,那么應(yīng)用程序應(yīng)該怎樣訪問具體的硬件設(shè)備呢?或者說已經(jīng)確定他是一個男人了,那么怎么從萬千世界中區(qū)分他與他的不同呢?答案是:姓名,在linux驅(qū)動中也就是設(shè)備文件名。那么重名怎么辦?答案是:身份證號,在linux驅(qū)動中也就是設(shè)備號(主、從)。設(shè)備文件:在linux系統(tǒng)中有一個約定俗成的說法:“一切皆文件”,應(yīng)用程序使用設(shè)備文件節(jié)點(diǎn)訪問對應(yīng)設(shè)備,Linux下的各種硬件設(shè)備以文件的形式存放于/dev目錄下,可以使用ls /dev 查看Linux把對硬件的操作全部抽象成對文件的操作(open,read,write,close,)每個設(shè)備文件都有其文件屬性(c或者b),使用ls /dev -l 的命令查看, 表明其是字符設(shè)備或者塊設(shè)備,網(wǎng)絡(luò)設(shè)備沒有在這個文件夾下,用來明其性別(男人、女人)主設(shè)備號、從設(shè)備號在設(shè)備管理中,除了設(shè)備類型外,內(nèi)核還需要一對被稱為主從設(shè)備號的參數(shù),才能唯一標(biāo)識一個設(shè)備,類似人的身份證號主設(shè)備號: 用于標(biāo)識驅(qū)動程序,相同的主設(shè)備號使用相同的驅(qū)動程序,例如:S3C2440 有串口、LCD、觸摸屏三種設(shè)備,他們的主設(shè)備號各不相同;從設(shè)備號: 用于標(biāo)識同一驅(qū)動程序的不同硬件 例:PC的IDE設(shè)備,主設(shè)備號用于標(biāo)識該硬盤,從設(shè)備號用于標(biāo)識每個分區(qū),2440有三個串口,每個串口的主設(shè)備號相同,從設(shè)備號用于區(qū)分具體屬于那一個串口。四、驅(qū)動程序與應(yīng)用程序的區(qū)別應(yīng)用程序以main開始驅(qū)動程序沒有main,它以一個模塊初始化函數(shù)作為入口應(yīng)用程序從頭到尾執(zhí)行一個任務(wù)驅(qū)動程序完成初始化之后不再運(yùn)行,等待系統(tǒng)調(diào)用應(yīng)用程序可以使用glibc等標(biāo)準(zhǔn)C函數(shù)庫驅(qū)動程序不能使用標(biāo)準(zhǔn)C庫五、用戶態(tài)與內(nèi)核態(tài)的區(qū)分驅(qū)動程序是內(nèi)核的一部分,工作在內(nèi)核態(tài)應(yīng)用程序工作在用戶態(tài)數(shù)據(jù)空間訪問問題無法通過指針直接將二者的數(shù)據(jù)地址進(jìn)行傳遞系統(tǒng)提供一系列函數(shù)幫助完成數(shù)據(jù)空間轉(zhuǎn)換get_userput_usercopy_from_usercopy_to_user六、Linux驅(qū)動程序功能對設(shè)備初始化和釋放資源把數(shù)據(jù)從內(nèi)核傳送到硬件和從硬件讀取數(shù)據(jù)讀取應(yīng)用程序傳送給設(shè)備文件的數(shù)據(jù)和回送應(yīng)用程序請求的數(shù)據(jù)檢測和處理設(shè)備出現(xiàn)的錯誤(底層協(xié)議)用于區(qū)分具體設(shè)備的實(shí)例一、linux內(nèi)核模塊簡介 linux內(nèi)核整體結(jié)構(gòu)非常龐大,其包含的組件也非常多。我們怎么把需要的部分都包含在內(nèi)核中呢?本篇文章來源于 Linux公社網(wǎng)站() 一種辦法是把所有的需要的功能都編譯到內(nèi)核中。這會導(dǎo)致兩個問題,一是生成的內(nèi)核會很大,二是如果我們要在現(xiàn)有的內(nèi)核中新增或刪除功能,不得不重新編譯內(nèi)核,工作效率會非常的低,同時如果編譯的模塊不是很完善,很有可能會造成內(nèi)核崩潰。 linux提供了另一種機(jī)制來解決這個問題,這種集中被稱為模塊,可以實(shí)現(xiàn)編譯出的內(nèi)核本身并不含有所有功能,而在這些功能需要被使用的時候,其對應(yīng)的代碼可以被動態(tài)的加載到內(nèi)核中。二、模塊特點(diǎn): 1)模塊本身并不被編譯入內(nèi)核,從而控制了內(nèi)核的大小。 2)模塊一旦被加載,他就和內(nèi)核中的其他部分完全一樣。 注意:模塊并不是驅(qū)動的必要形式:即:驅(qū)動不一定必須是模塊,有些驅(qū)動是直接編譯進(jìn)內(nèi)核的;同時模塊也不全是驅(qū)動,例如我們寫的一些很小的算法可以作為模塊編譯進(jìn)內(nèi)核,但它并不是驅(qū)動。就像燒餅不一定是圓的,圓的也不都是燒餅一樣。三、最簡單的模塊分析1)以下是一個最簡單的模塊例子#include /* printk() */#include /* _init _exit */static int _init hello_init(void) /*模塊加載函數(shù),通過insmod命令加載模塊時,被自動執(zhí)行*/ printk(KERN_INFO Hello World entern); return 0;static void _exit hello_exit(void) /*模塊卸載函數(shù),當(dāng)通過rmmod命令卸載時,會被自動執(zhí)行*/ printk(KERN_INFO Hello World exitn );module_init(hello_init);module_exit(hello_exit);MODULE_AUTHOR(dengwei); /*模塊作者,可選*/MODULE_LICENSE(Dual BSD/GPL); /*模塊許可證明,描述內(nèi)核模塊的許可權(quán)限,必須*/MODULE_DESCRIPTION(A simple Hello World Module); /*模塊說明,可選*/MODULE_ALIAS(a simplest module); /*模塊說明,可選*/2) 以下是編譯上述模塊所需的編寫的makefileobj-m :=hello.o /目標(biāo)文件#module-objs := file1.o file.o /當(dāng)模塊有多個文件組成時,添加本句KDIR :=/usr/src/linux /內(nèi)核路徑,根據(jù)實(shí)際情況換成自己的內(nèi)核路徑,嵌入式的換成嵌入式,PC機(jī)的指定PC機(jī)路徑PWD := $(shell pwd) /模塊源文件路徑all: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules rm -rf *.mod.* rm -rf .*.cmd rm -rf *.o rm -rf Module.*clean: rm -rf *.ko最終會編譯得到:hello.ko文件使用insmodhello.ko將模塊插入內(nèi)核,然后使用dmesg即可看到輸出提示信息。常用的幾種模塊操作:insmod XXX.ko 加載指定模塊lsmod 列舉當(dāng)前系統(tǒng)中的所有模塊rmmod XXX 卸載指定模塊(注意沒有.ko后綴)dmesg 當(dāng)打印等級低于默認(rèn)輸出等級時,采用此命令查看系統(tǒng)日志3)linux內(nèi)核模塊的程序結(jié)構(gòu)1.模塊加載函數(shù):Linux內(nèi)核模塊一般以_init標(biāo)示聲明,典型的模塊加載函數(shù)的形式如下:static int _init myModule_init(void) /* Module init code */ PRINTK(myModule_initn); return 0;module_init(myModule_init);模塊加載函數(shù)的名字可以隨便取,但必須以“module_init(函數(shù)名)”的形式被指定;執(zhí)行insmod命令時被執(zhí)行,用于初始化模塊所必需資源,比如內(nèi)存空間、硬件設(shè)備等;它返回整形值,若初始化成功,應(yīng)返回0,初始化失敗返回負(fù)數(shù)。2.模塊卸載函數(shù)典型的模塊卸載函數(shù)形式如下:static void _exit myModule_exit(void) /* Module exit code */ PRINTK(myModule_exitn); return;module_exit(myModule_exit);模塊卸載函數(shù)在模塊卸載的時候執(zhí)行,不返回任何值,需用”module_exit(函數(shù)名)”的形式被指定。卸載模塊完成與加載函數(shù)相反的功能: 若加載函數(shù)注冊了XXX,則卸載函數(shù)應(yīng)當(dāng)注銷XXX 若加載函數(shù)申請了內(nèi)存空間,則卸載函數(shù)應(yīng)當(dāng)釋放相應(yīng)的內(nèi)存空間 若加載函數(shù)申請了某些硬件資源(中斷、DMA、I/0端口、I/O內(nèi)存等),則卸載函數(shù)應(yīng)當(dāng)釋放相應(yīng)的硬件資源 若加載函數(shù)開啟了硬件,則卸載函數(shù)應(yīng)當(dāng)關(guān)閉硬件。其中_init 、_exit 為系統(tǒng)提供的兩種宏,表示其所修飾的函數(shù)在調(diào)用完成后會自動回收內(nèi)存,即內(nèi)核認(rèn)為這種函數(shù)只會被執(zhí)行1次,然后他所占用的資源就會被釋放。3.模塊聲明與描述 在linux內(nèi)核模塊中,我們可以用MODULE_AUTHOR、MODULE_DESCRIPTION、MODULE_VERSION、MODULE_TABLE、MODULE_ALIA,分別描述模塊的作者、描述、版本、設(shè)備表號、別名等。MODULE_AUTHOR(dengwei);MODULE_LICENSE(Dual BSD/GPL);MODULE_DESCRIPTION(A simple Hello World Module);MODULE_ALIAS(a simplest module);四、有關(guān)模塊的其它特性1)模塊參數(shù):我們可以利用module_param(參數(shù)名、參數(shù)類型、參數(shù)讀寫屬性) 為模塊定義一個參數(shù),例如:static char *string_test = “this is a test”;static num_test = 1000;module_param (num_test,int,S_IRUGO);module_param (steing_test,charp,S_ITUGO); 在裝載模塊時,用戶可以給模塊傳遞參數(shù),形式為:”insmod 模塊名 參數(shù)名=參數(shù)值”,如果不傳遞,則參數(shù)使用默認(rèn)的參數(shù)值 參數(shù)的類型可以是:byte,short,ushort,int,uint,long,ulong,charp,bool; 權(quán)限:定義在linux/stat.h中,控制存取權(quán)限,S_IRUGO表示所有用戶只讀; 模塊被加載后,在sys/module/下會出現(xiàn)以此模塊命名的目錄,當(dāng)讀寫權(quán)限為零時:表示此參數(shù)不存在sysfs文件系統(tǒng)下的文件節(jié)點(diǎn),當(dāng)讀寫權(quán)限不為零時:此模塊的目錄下會存在parameters目錄,包含一系列以參數(shù)名命名的文件節(jié)點(diǎn),這些文件節(jié)點(diǎn)的權(quán)限值就是傳入module_param()的“參數(shù)讀/寫權(quán)限“,而該文件的內(nèi)容為參數(shù)的值。 除此之外,模塊也可以擁有參數(shù)數(shù)組,形式為:”module_param_array(數(shù)組名、數(shù)組類型、數(shù)組長、參數(shù)讀寫權(quán)限等)”,當(dāng)不需要保存實(shí)際的輸入的數(shù)組元素的個數(shù)時,可以設(shè)置“數(shù)組長“為0。 運(yùn)行insmod時,使用逗號分隔輸入的數(shù)組元素。下面是一個實(shí)際的例子,來說明模塊傳參的過程。#include /*module_init()*/#include /* printk() */#include /* _init _exit */#define DEBUG /open debug message#ifdef DEBUG#define PRINTK(fmt, arg.) printk(KERN_WARNING fmt, #arg)#else#define PRINTK(fmt, arg.) printk(KERN_DEBUG fmt, #arg)#endifstatic char *string_test=default paramater;static int num_test=1000;static int _init hello_init(void) PRINTK(nthe string_test is : %sn,string_test); PRINTK(the num_test is : %dn,num_test); return 0;static void _exit hello_exit(void) PRINTK( input paramater module exitn );module_init(hello_init);module_exit(hello_exit);module_param(num_test,int,S_IRUGO);module_param(string_test,charp,S_IRUGO);MODULE_AUTHOR(dengwei);MODULE_LICENSE(GPL);當(dāng)執(zhí)行 insmod hello_param.ko時,執(zhí)行dmesg 查看內(nèi)核輸出信息:Hello World enterthe test string is: this is a testthe test num is :1000當(dāng)執(zhí)行insmod hello_param.ko num_test=2000 string_test=“edit by dengwei”,執(zhí)行dmesg查看內(nèi)核輸出信息:Hello World enterthe test string is: edit by dengweithe test num is :20002)導(dǎo)出模塊及符號的相互引用Linux2.6內(nèi)核的“/proc/kallsyms“文件對應(yīng)內(nèi)核符號表,它記錄了符號以及符號所在的內(nèi)存地址,模塊可以使用下列宏導(dǎo)到內(nèi)核符號表中。EXPORT_SYMBOL(符號名); 任意模塊均可EXPORT_SYMBOL_GPL(符號名); 只使用于包含GPL許可權(quán)的模塊導(dǎo)出的符號可以被其它模塊使用,使用前聲明一下即可。下面給出一個簡單的例子:將add sub符號導(dǎo)出到內(nèi)核符號表中,這樣其它的模塊就可以利用其中的函數(shù)#include /*module_init()*/#include /* printk() */#include /* _init _exit */int add_test(int a ,int b) return a + b;int sub_test(int a,int b) return a - b;EXPORT_SYMBOL(add_test);EXPORT_SYMBOL(sub_test);MODULE_AUTHOR(dengwei);MODULE_LICENSE(GPL);執(zhí)行 cat/proc/kallsyms | grep test 即可找到以下信息,表示模塊確實(shí)被加載到內(nèi)核表中。f88c9008 r _ksymtab_sub_integar export_symbf88c9020 r _kstrtab_sub_integar export_symbf88c9018 r _kcrctab_sub_integar export_symbf88c9010 r _ksymtab_add_integar export_symbf88c902c r _kstrtab_add_integar export_symbf88c901c r _kcrctab_add_integar export_symbf88c9000 T add_tes export_symbf88c9004 T sub_tes export_symb13db98c9 a _crc_sub_integar export_symbe1626dee a _crc_add_integar export_symb在其它模塊中可以引用此符號#include /*module_init()*/#include /* printk() */#include /* _init _exit */#define DEBUG /open debug message#ifdef DEBUG#define PRINTK(fmt, arg.) printk(KERN_WARNING fmt, #arg)#else#define PRINTK(fmt, arg.) printk(KERN_DEBUG fmt, #arg)#endifextern int add_test(int a ,int b);extern int sub_test(int a,int b);static int _init hello_init(void) int a,b; a = add_test(10,20); b = sub_test(30,20); PRINTK(the add test result is %d,a); PRINTK(the sub test result is %dn,b); return 0;static void _exit hello_exit(void) PRINTK( Hello World exitn );module_init(hello_init);module_exit(hello_exit);MODULE_AUTHOR(dengwei);MODULE_LICENSE(GPL);前面我們介紹模塊編程的時候介紹了驅(qū)動進(jìn)入內(nèi)核有兩種方式:模塊和直接編譯進(jìn)內(nèi)核,并介紹了模塊的一種編譯方式在一個獨(dú)立的文件夾通過makefile配合內(nèi)核源碼路徑完成 - 那么如何將驅(qū)動直接編譯進(jìn)內(nèi)核呢? 在我們實(shí)際內(nèi)核的移植配置過程中經(jīng)常聽說的內(nèi)核裁剪又是怎么麼回事呢?我們在進(jìn)行l(wèi)inux內(nèi)核配置的時候經(jīng)常會執(zhí)行make menuconfig這個命令,然后屏幕上會出現(xiàn)以下界面:這個界面是怎么生成的呢?跟我們經(jīng)常說的內(nèi)核配置與與編譯又有什么關(guān)系呢?下面我們借此來講解一下linux內(nèi)核的配置機(jī)制及其編譯過程。一、配置系統(tǒng)的基本結(jié)構(gòu)Linux內(nèi)核的配置系統(tǒng)由三個部分組成,分別是: 1、Makefile:分布在 Linux 內(nèi)核源代碼根目錄及各層目錄中,定義 Linux 內(nèi)核的編譯規(guī)則; 2、配置文件(config.in(2.4內(nèi)核,2.6內(nèi)核)):給用戶提供配置選擇的功能; 3、配置工具:包括配置命令解釋器(對配置腳本中使用的配置命令進(jìn)行解釋)和配置用戶界面(提供基于字符界面、基于 Ncurses 圖形界面以及基于 Xwindows 圖形界面的用戶配置界面,各自對應(yīng)于 Make config、Make menuconfig 和 make xconfig)。 這些配置工具都是使用腳本語言,如 Tcl/TK、Perl 編寫的(也包含一些用 C 編寫的代碼)。本文并不是對配置系統(tǒng)本身進(jìn)行分析,而是介紹如何使用配置系統(tǒng)。所以,除非是配置系統(tǒng)的維護(hù)者,一般的內(nèi)核開發(fā)者無須了解它們的原理,只需要知道如何編寫 Makefile 和配置文件就可以。二、makefile menuconfig過程講解當(dāng)我們在執(zhí)行make menuconfig這個命令時,系統(tǒng)到底幫我們做了哪些工作呢?這里面一共涉及到了一下幾個文件我們來一一講解Linux內(nèi)核根目錄下的scripts文件夾arch/$ARCH/Kconfig文件、各層目錄下的Kconfig文件Linux內(nèi)核根目錄下的makefile文件、各層目錄下的makefile文件Linux內(nèi)核根目錄下的的.config文件、arm/$ARCH/下的config文件Linux內(nèi)核根目錄下的 include/generated/autoconf.h文件1)scripts文件夾存放的是跟make menuconfig配置界面的圖形繪制相關(guān)的文件,我們作為使用者無需關(guān)心這個文件夾的內(nèi)容2)當(dāng)我們執(zhí)行make menuconfig命令出現(xiàn)上述藍(lán)色配置界面以前,系統(tǒng)幫我們做了以下工作: 首先系統(tǒng)會讀取arch/$ARCH/目錄下的Kconfig文件生成整個配置界面選項(xiàng)(Kconfig是整個linux配置機(jī)制的核心),那么ARCH環(huán)境變量的值等于多少呢?它是由linux內(nèi)核根目錄下的makefile文件決定的,在makefile下有此環(huán)境變量的定義:或者通過 make ARCH=arm menuconfig命令來生成配置界面,默認(rèn)生成的界面是所有參數(shù)都是沒有值的 比如教務(wù)處進(jìn)行考試,考試科數(shù)可能有外語、語文、數(shù)學(xué)等科,這里相當(dāng)于我們選擇了arm科可進(jìn)行考試,系統(tǒng)就會讀取arm/arm/kconfig文件生成配置選項(xiàng)(選擇了arm科的卷子),系統(tǒng)還提供了x86科、milps科等10幾門功課的考試題3)假設(shè)教務(wù)處比較“仁慈”,為了怕某些同學(xué)做不錯試題,還給我們準(zhǔn)備了一份參考答案(默認(rèn)配置選項(xiàng)),存放在arch/$ARCH/configs下,對于arm科來說就是arch/arm/configs文件夾: 此文件夾中有許多選項(xiàng),系統(tǒng)會讀取哪個呢?內(nèi)核默認(rèn)會讀取linux內(nèi)核根目錄下.config文件作為內(nèi)核的默認(rèn)選項(xiàng)(試題的參考答案),我們一般會根據(jù)開發(fā)板的類型從中選取一個與我們開發(fā)板最接近的系列到Linux內(nèi)核根目錄下(選擇一個最接近的參考答案)#cp arch/arm/configs/s3c2410_defconfig .config4).config 假設(shè)教務(wù)處留了一個心眼,他提供的參考答案并不完全正確(.config文件與我們的板子并不是完全匹配),這時我們可以選擇直接修改.config文件然后執(zhí)行make menuconfig命令讀取新的選項(xiàng) 但是一般我們不采取這個方案,我們選擇在配置界面中通過空格、esc、回車選擇某些選項(xiàng)選中或者不選中,最后保存退出的時候,Linux內(nèi)核會把新的選項(xiàng)(正確的參考答案)更新到.config中,此時我們可以把.config重命名為其它文件保存起來(當(dāng)你執(zhí)行make distclean時系統(tǒng)會把.config文件刪除),以后我們再配置內(nèi)核時就不需要再去arch/arm/configs下考取相應(yīng)的文件了,省去了重新配置的麻煩,直接將保存的.config文件復(fù)制為.config即可.5)經(jīng)過以上兩步,我們可以正確的讀取、配置我們需要的界面了那么他們?nèi)绾胃鷐akefile文件建立編譯關(guān)系呢?當(dāng)你保存make menuconfig選項(xiàng)時,系統(tǒng)會除了會自動更新.config外,還會將所有的選項(xiàng)以宏的形式保存在Linux內(nèi)核根目錄下的 include/generated/autoconf.h文件下內(nèi)核中的源代碼就都會包含以上.h文件,跟宏的定義情況進(jìn)行條件編譯。當(dāng)我們需要對一個文件整體選擇如是否編譯時,還需要修改對應(yīng)的makefile文件,例如: 我們選擇是否要編譯s3c2410_ts.c這個文件時,makefile會根據(jù)CONFIG_TOUCHSCREEN_S3C2410來決定是編譯此文件,此宏是在Kconfig文件中定義,當(dāng)我們配置完成后,會出現(xiàn)在.config及autconf中,至此,我們就完成了整個linux內(nèi)核的編譯過程。 最后我們會發(fā)現(xiàn),整個linux內(nèi)核配置過程中,留給用戶的接口其實(shí)只有各層Kconfig、makefile文件以及對應(yīng)的源文件。 比如我們?nèi)绻胍o內(nèi)核增加一個功能,并且通過make menuconfig控制其聲稱過程 首先需要做的工作是:修改對應(yīng)目錄下的Kconfig文件,按照Kconfig語法增加對應(yīng)的選項(xiàng); 其次執(zhí)行make menuconfig選擇編譯進(jìn)內(nèi)核或者不編譯進(jìn)內(nèi)核,或者編譯為模塊,.config文件和autoconf.h文件會自動生成; 最后修改對應(yīng)目錄下的makefile文件完成編譯選項(xiàng)的添加; 最后的最后執(zhí)行make zImage命令進(jìn)行編譯。三、具體實(shí)例下面我們以前面做過的模塊實(shí)驗(yàn)為例,講解如何通過make menuconfig機(jī)制將前面單獨(dú)編譯的模塊編譯進(jìn)內(nèi)核或編譯為模塊假設(shè)我已經(jīng)有了這么一個驅(qū)動:modules.c#include /*module_init()*/#include

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論