嵌入式系統(tǒng)軟件開(kāi)發(fā)技術(shù)BSP和驅(qū)動(dòng).ppt_第1頁(yè)
嵌入式系統(tǒng)軟件開(kāi)發(fā)技術(shù)BSP和驅(qū)動(dòng).ppt_第2頁(yè)
嵌入式系統(tǒng)軟件開(kāi)發(fā)技術(shù)BSP和驅(qū)動(dòng).ppt_第3頁(yè)
嵌入式系統(tǒng)軟件開(kāi)發(fā)技術(shù)BSP和驅(qū)動(dòng).ppt_第4頁(yè)
嵌入式系統(tǒng)軟件開(kāi)發(fā)技術(shù)BSP和驅(qū)動(dòng).ppt_第5頁(yè)
已閱讀5頁(yè),還剩174頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、嵌入式系統(tǒng)軟件開(kāi)發(fā)技術(shù),嵌入式系統(tǒng),主要內(nèi)容,版級(jí)支持包 BSP 嵌入式系統(tǒng)初始化以及BSP的設(shè)計(jì) Linux系統(tǒng)驅(qū)動(dòng)程序開(kāi)發(fā) 嵌入式聯(lián)網(wǎng),BSP的概念,BSP全稱“板級(jí)支持包”(Board Support Packages),說(shuō)的簡(jiǎn)單一點(diǎn),就是一段啟動(dòng)代碼,和計(jì)算機(jī)主板的BIOS差不多,但提供的功能區(qū)別就相差很大 在Windows CE中,BSP是驅(qū)動(dòng)程序、OEM適應(yīng)層(OEM Adaptation Layers,OAL)、硬件抽象層(HAL)以及啟動(dòng)設(shè)備和使外設(shè)正常工作所需BIOS文件的集合,BSP和BIOS區(qū)別,BIOS主要是負(fù)責(zé)在電腦開(kāi)啟時(shí)檢測(cè)、初始化系統(tǒng)設(shè)備(設(shè)置棧指針,中斷分配,內(nèi)

2、存初始化.)、裝入操作系統(tǒng)并調(diào)度操作系統(tǒng)向硬件發(fā)出的指令。 BSP是和操作系統(tǒng)綁在一起運(yùn)行,盡管BSP的開(kāi)始部分和BIOS所做的工作類(lèi)似,但是 BSP還包含和系統(tǒng)有關(guān)的基本驅(qū)動(dòng) BIOS程序是用戶不能更改,編譯編程的,只能對(duì)參數(shù)進(jìn)行修改設(shè)置,但是程序員還可以編程修改BSP,在BSP中任意添加一些和系統(tǒng)無(wú)關(guān)的驅(qū)動(dòng)或程序,甚至可以把上層開(kāi)發(fā)的統(tǒng)統(tǒng)放到BSP中,不同系統(tǒng)中的BSP,一個(gè)嵌入式操作系統(tǒng)針對(duì)不同的CPU,會(huì)有不同的BSP 即使同一種CPU,由于外設(shè)的一點(diǎn)差別BSP相應(yīng)的部分也不一樣,BSP的特點(diǎn)與功能,硬件相關(guān)性 因?yàn)榍度胧綄?shí)時(shí)系統(tǒng)的硬件環(huán)境具有應(yīng)用相關(guān)性,所以,作為高層軟件與硬件之間的

3、接口,BSP必須為操作系統(tǒng)提供操作和控制具體硬件的方法。 操作系統(tǒng)相關(guān)性 不同的操作系統(tǒng)具有各自的軟件層次結(jié)構(gòu),因此,不同的操作系統(tǒng)具有特定的硬件接口形式,BSP的設(shè)計(jì)與實(shí)現(xiàn),為實(shí)現(xiàn)上述兩部分功能,設(shè)計(jì)一個(gè)完整的BSP需要完成兩部分工作: 設(shè)計(jì)初始化過(guò)程,完成嵌入式系統(tǒng)的初始化; 設(shè)計(jì)硬件相關(guān)的設(shè)備驅(qū)動(dòng),完成操作系統(tǒng)及應(yīng)用程序?qū)唧w硬件的操作,嵌入式系統(tǒng)初始化以及BSP的功能,嵌入式系統(tǒng)的初始化過(guò)程是一個(gè)同時(shí)包括硬件初始化和軟件初始化的過(guò)程;而操作系統(tǒng)啟動(dòng)以前的初始化操作是BSP的主要功能之一 初始化過(guò)程總可以抽象為三個(gè)主要環(huán)境,按照自底向上、從硬件到軟件的次序依次為: 片級(jí)初始化 板級(jí)初始化

4、 系統(tǒng)級(jí)初始化,初始化過(guò)程,片級(jí)初始化: 主要完成CPU的初始化 設(shè)置CPU的核心寄存器和控制寄存器 CPU核心工作模式 CPU的局部總線模式等 片級(jí)初始化把CPU從上電時(shí)的缺省狀態(tài)逐步設(shè)置成為系統(tǒng)所要求的工作狀態(tài) 這是一個(gè)純硬件的初始化過(guò)程,初始化過(guò)程(續(xù)1,板級(jí)初始化: 完成CPU以外的其他硬件設(shè)備的初始化 同時(shí)還要設(shè)置某些軟件的數(shù)據(jù)結(jié)構(gòu)和參數(shù),為隨后的系統(tǒng)級(jí)初始化和應(yīng)用程序的運(yùn)行建立硬件和軟件環(huán)境 這是一個(gè)同時(shí)包含軟硬件兩部分在內(nèi)的初始化過(guò)程,初始化過(guò)程(續(xù)2,系統(tǒng)級(jí)初始化: 這是一個(gè)以軟件初始化為主的過(guò)程,主要進(jìn)行操作系統(tǒng)初始化 BSP將控制轉(zhuǎn)交給操作系統(tǒng),由操作系統(tǒng)進(jìn)行余下的初始化操

5、作: 包括加載和初始化與硬件無(wú)關(guān)的設(shè)備驅(qū)動(dòng)程序 建立系統(tǒng)內(nèi)存區(qū) 加載并初始化其他系統(tǒng)軟件模塊(如網(wǎng)絡(luò)系統(tǒng)、文件系統(tǒng)等) 最后,操作系統(tǒng)創(chuàng)建應(yīng)用程序環(huán)境并將控制轉(zhuǎn)交給應(yīng)用程序的入口,硬件相關(guān)的設(shè)備驅(qū)動(dòng)程序,BSP另一個(gè)主要功能是硬件相關(guān)的設(shè)備驅(qū)動(dòng) 與初始化過(guò)程相反,硬件相關(guān)的設(shè)備驅(qū)動(dòng)程序的初始化和使用通常是一個(gè)從高層到底層的過(guò)程 盡管BSP中包含硬件相關(guān)的設(shè)備驅(qū)動(dòng)程序,但是這些設(shè)備驅(qū)動(dòng)程序通常不直接由BSP使用 而是在系統(tǒng)初始化過(guò)程中由BSP把它們與操作系統(tǒng)中通用的設(shè)備驅(qū)動(dòng)程序關(guān)聯(lián)起來(lái),并在隨后的應(yīng)用中由通用的設(shè)備驅(qū)動(dòng)程序調(diào)用,實(shí)現(xiàn)對(duì)硬件設(shè)備的操作,BSP開(kāi)發(fā)的前提和步驟,開(kāi)發(fā)的前提 : 熟悉硬

6、件方面:使用CPU等 熟悉工具方面:電表,示波器,邏輯分析儀,硬件仿真器,仿真調(diào)試環(huán)境等 語(yǔ)言方面:匯編語(yǔ)言,C語(yǔ)言 BSP開(kāi)發(fā)的一般步驟如下: 硬件主板研制,測(cè)試 操作系統(tǒng)的選定,BSP編程 上層應(yīng)用程序的開(kāi)發(fā),編寫(xiě)B(tài)SP函數(shù),BSP對(duì)板卡中每個(gè)芯片的操作都通過(guò)多個(gè)函數(shù)來(lái)完成 如果應(yīng)用程序?qū)Π蹇ǖ牟僮鞫贾苯油ㄟ^(guò)調(diào)用BSP中的函數(shù)來(lái)完成,那將很不利于源程序的調(diào)試 ,并降低了程序的可移植性 把能完成某個(gè)特定功能的函數(shù)封裝在一個(gè)庫(kù)文件中,并放在應(yīng)用程序與BSP之間 對(duì)每個(gè)芯片來(lái)說(shuō),都應(yīng)當(dāng)有初始化函數(shù)和狀態(tài)讀取函數(shù),設(shè)計(jì)實(shí)現(xiàn)BSP的一般方法,BSP的開(kāi)發(fā)需要具備一定的硬件知識(shí) 要求掌握操作系統(tǒng)所定義

7、的BSP接口 兩種快捷方法 以經(jīng)典BSP為參考 使用操作系統(tǒng)提供的BSP模板 設(shè)計(jì)實(shí)現(xiàn)BSP兩部分功能時(shí)應(yīng)采用以下兩種不同方法 “自底向上”地實(shí)現(xiàn)BSP中的初始化操作 “自頂向下”地設(shè)計(jì)硬件相關(guān)的驅(qū)動(dòng)程序,BSP設(shè)計(jì)方法的不足與改進(jìn),目前BSP的設(shè)計(jì)與實(shí)現(xiàn)主要是針對(duì)某些特定的文件進(jìn)行修改 直接修改相關(guān)文件容易造成代碼的不一致性,增加軟件設(shè)計(jì)上的隱形錯(cuò)誤,從而增加系統(tǒng)調(diào)試和代碼維護(hù)的難度 解決這個(gè)問(wèn)題的一個(gè)可行辦法是:設(shè)計(jì)實(shí)現(xiàn)一種具有圖形界面的BSP開(kāi)發(fā)設(shè)計(jì)向?qū)?,由該向?qū)е笇?dǎo)設(shè)計(jì)者逐步完成BSP的設(shè)計(jì)和開(kāi)發(fā),并最終由向?qū)上鄳?yīng)的BSP文件,而不再由設(shè)計(jì)人員直接對(duì)源文件進(jìn)行修改,Linux設(shè)備驅(qū)

8、動(dòng)程序及開(kāi)發(fā),Linux設(shè)備驅(qū)動(dòng)程序概述,Linux設(shè)備驅(qū)動(dòng)程序是處理或操作硬件控制器的軟件,被集成在內(nèi)核中,是常駐內(nèi)存的低級(jí)硬件處理程序的共享庫(kù),設(shè)備驅(qū)動(dòng)程序是系統(tǒng)對(duì)設(shè)備的抽象管理與控制。 Linux允許設(shè)備驅(qū)動(dòng)程序作為內(nèi)核可加載模塊實(shí)現(xiàn),即除了可以在系統(tǒng)啟動(dòng)時(shí)進(jìn)行注冊(cè)外,還可以在啟動(dòng)后進(jìn)行加載注冊(cè),Linux驅(qū)動(dòng)程序開(kāi)發(fā),建立嵌入式Linux平臺(tái),移植和編寫(xiě)驅(qū)動(dòng)程序往往是最具挑戰(zhàn)的工作 驅(qū)動(dòng)程序的開(kāi)發(fā)周期一般較長(zhǎng),對(duì)產(chǎn)品的面世時(shí)間有著重要影響 驅(qū)動(dòng)程序質(zhì)量的好壞,直接關(guān)系到系統(tǒng)工作效能和穩(wěn)定性,對(duì)項(xiàng)目的成敗起著關(guān)鍵作用,設(shè)備驅(qū)動(dòng)程序主要功能,設(shè)備驅(qū)動(dòng)程序主要完成如下功能: 檢測(cè)設(shè)備和初始化

9、設(shè)備 使設(shè)備投入運(yùn)行和退出服務(wù) 從設(shè)備接收數(shù)據(jù)并提交給內(nèi)核 從內(nèi)核接收數(shù)據(jù)送到設(shè)備 檢測(cè)和處理設(shè)備錯(cuò)誤,Linux設(shè)備驅(qū)動(dòng)程序分類(lèi),Linux中所有設(shè)備被抽象出來(lái),都看成文件 設(shè)備的讀寫(xiě)和普通文件一樣 Linux系統(tǒng)的設(shè)備分為如下三類(lèi): 字符設(shè)備(char device) 塊設(shè)備(block device) 網(wǎng)絡(luò)設(shè)備(network device) 字符設(shè)備是指存取時(shí)沒(méi)有緩存的設(shè)備 塊設(shè)備的讀寫(xiě)都有緩存來(lái)支持,且塊設(shè)備必須能夠隨機(jī)存取(random access) 網(wǎng)絡(luò)設(shè)備在Linux里做專門(mén)的處理,Linux設(shè)備驅(qū)動(dòng)程序分類(lèi),網(wǎng)絡(luò)設(shè)備在Linux里做專門(mén)的處理 Linux的網(wǎng)絡(luò)系統(tǒng)主要是基于

10、BSD unix的socket 機(jī)制。在系統(tǒng)和驅(qū)動(dòng)程序之間定義有專門(mén)的數(shù)據(jù)結(jié)構(gòu)(sk_buff)進(jìn)行數(shù)據(jù)的傳遞 系統(tǒng)里支持對(duì)發(fā)送數(shù)據(jù)和接收數(shù)據(jù)的緩存,提供流量控制機(jī)制,提供對(duì)多協(xié)議的支持,Linux設(shè)備驅(qū)動(dòng)程序分類(lèi),典型的字符設(shè)備包括鼠標(biāo),鍵盤(pán),串行口等 塊設(shè)備主要包括硬盤(pán)、軟盤(pán)設(shè)備、CD-ROM等 一個(gè)文件系統(tǒng)要安裝進(jìn)入操作系統(tǒng)必須在塊設(shè)備上,Linux驅(qū)動(dòng)程序介紹,嵌入式Linux驅(qū)動(dòng)已經(jīng)支持的設(shè)備門(mén)類(lèi)齊全,已成為其相對(duì)其他嵌入式操作系統(tǒng)的一大優(yōu)勢(shì) 工業(yè)控制常用的串口,并口 人機(jī)輸入設(shè)備如鼠標(biāo)、鍵盤(pán),觸摸屏 彩色、黑白液晶顯示輸出 網(wǎng)絡(luò)的完善支持,包括tcp/ip,udp,firewall

11、,WLAN,ip forwarding,ipsec,vpn Usb的全面支持,包括usb硬盤(pán)、u盤(pán),usb攝像頭 支持豐富的文件系統(tǒng),包括FAT32,NTFS,嵌入式設(shè)備框圖,驅(qū)動(dòng)程序的功用,1、驅(qū)動(dòng)程序直接操控硬件 收發(fā)通訊數(shù)據(jù) 讀寫(xiě)存儲(chǔ)介質(zhì),比如flash或硬盤(pán) 操作輸出設(shè)備和執(zhí)行機(jī)構(gòu),例如打印,開(kāi)關(guān)門(mén)禁等,驅(qū)動(dòng)程序的功用(續(xù),2、驅(qū)動(dòng)程序提供軟件訪問(wèn)硬件的機(jī)制 應(yīng)用軟件通過(guò)驅(qū)動(dòng)程序安全高效的訪問(wèn)硬件 驅(qū)動(dòng)程序文件可以方便的提供訪問(wèn)權(quán)限控制 驅(qū)動(dòng)程序作為一個(gè)隔離的中間層軟件,將底 層細(xì)節(jié)隱藏起來(lái),提高了軟件的可移植性,訪問(wèn)Linux設(shè)備驅(qū)動(dòng)的方法,設(shè)備提供dev文件系統(tǒng)節(jié)點(diǎn)和proc文 件

12、系統(tǒng)節(jié)點(diǎn) 應(yīng)用程序通過(guò)dev文件節(jié)點(diǎn)訪問(wèn)驅(qū)動(dòng) 程序 應(yīng)用程序通過(guò)proc文件節(jié)點(diǎn)可以查 詢?cè)O(shè)備驅(qū)動(dòng)的信息,驅(qū)動(dòng)程序位置,驅(qū)動(dòng)程序位于drivers目錄下 通常驅(qū)動(dòng)程序占kernel代碼的50% Linux設(shè)備驅(qū)動(dòng)程序在Linux的內(nèi)核源代碼中占有很大的比例,源代碼的長(zhǎng)度日益增加,主要是驅(qū)動(dòng)程序的增加。 在Linux內(nèi)核的不斷升級(jí)過(guò)程中,驅(qū)動(dòng)程序的結(jié)構(gòu)還是相對(duì)穩(wěn)定。 在2.0.xx到2.2.xx的變動(dòng)里,驅(qū)動(dòng)程序的編寫(xiě)做了一些改變,但是從2.0.xx的驅(qū)動(dòng)到2.2.xx的移植只需做少量的工作,Linux驅(qū)動(dòng)程序的特點(diǎn),嵌入式Linux驅(qū)動(dòng)程序需求多樣 嵌入式設(shè)備硬件各異 嵌入式計(jì)算平臺(tái)往往資源有

13、限,比如處理速度、存儲(chǔ)器容量、總線帶寬、電池容量等 通常要求短的開(kāi)發(fā)周期、壓力大 開(kāi)發(fā)驅(qū)動(dòng)程序需要豐富的專業(yè)知識(shí),包括 硬件和軟件知識(shí),嵌入式Linux驅(qū)動(dòng)程序特點(diǎn),嵌入式系統(tǒng)硬件更新速度加快 國(guó)際上大的嵌入式芯片提供商如Intel、 Samsung、Freescale、TI、ST每年都有大量新品推出 新的芯片功能總是需要相應(yīng)的驅(qū)動(dòng)程序支持,Linux驅(qū)動(dòng)開(kāi)發(fā)流程,熟悉設(shè)備的特性 確定設(shè)備驅(qū)動(dòng)程序類(lèi)別 編寫(xiě)測(cè)試用例 搜集可重用的代碼 編寫(xiě)自己的驅(qū)動(dòng)程序代碼 編碼、調(diào)試、測(cè)試,Linux驅(qū)動(dòng)程序的開(kāi)發(fā)環(huán)境,本機(jī)編譯調(diào)試 開(kāi)發(fā)環(huán)境配置簡(jiǎn)單 無(wú)需網(wǎng)絡(luò)環(huán)境 適用于配置較高的x86機(jī)器 主機(jī)+目標(biāo)機(jī) 主

14、機(jī)可以自由選擇Linux或Windows+Cygwin 主機(jī)和目標(biāo)機(jī)通過(guò)網(wǎng)絡(luò)共享文件系統(tǒng) 內(nèi)核崩潰不會(huì)影響主機(jī),Linux驅(qū)動(dòng)程序的開(kāi)發(fā)環(huán)境(續(xù),主機(jī)+目標(biāo)機(jī)環(huán)境包括 主機(jī)運(yùn)行的工具鏈cross gcc + glibc + gdb, 如果是windows主機(jī)還要有cygwin仿真環(huán)境 主機(jī)運(yùn)行遠(yuǎn)程服務(wù),常用的有tftp用來(lái)傳送內(nèi) 核映像、initrd,NFS用來(lái)共享文件系統(tǒng) 目標(biāo)機(jī)運(yùn)行ssh或telnet等遠(yuǎn)程登陸服務(wù),用來(lái) 調(diào)試驅(qū)動(dòng)程序,Linux驅(qū)動(dòng)程序的加載方式,驅(qū)動(dòng)程序直接編譯入內(nèi)核 驅(qū)動(dòng)程序在內(nèi)核啟動(dòng)時(shí)就已經(jīng)在內(nèi)存中 可以保留專用存儲(chǔ)器空間 驅(qū)動(dòng)程序以模塊形式存儲(chǔ)在文件系 統(tǒng)里,需要

15、時(shí)動(dòng)態(tài)載入內(nèi)核 驅(qū)動(dòng)程序按需加載,不用時(shí)節(jié)省內(nèi)存 驅(qū)動(dòng)程序相對(duì)獨(dú)立于內(nèi)核,升級(jí)靈活,Linux驅(qū)動(dòng)程序模塊加載,Linux驅(qū)動(dòng)程序開(kāi)發(fā)的任務(wù),規(guī)劃硬件資源的使用 分離硬件相關(guān)和硬件無(wú)關(guān)的代碼 劃分驅(qū)動(dòng)程序的抽象層次 移植驅(qū)動(dòng)程序到新的平臺(tái),Linux驅(qū)動(dòng)程序開(kāi)發(fā)的任務(wù),規(guī)劃硬件資源的使用 CPU時(shí)間片分配 中斷處理 系統(tǒng)存儲(chǔ)器空間映射,設(shè)備存儲(chǔ)器的映射,Linux驅(qū)動(dòng)程序開(kāi)發(fā)的任務(wù),分離硬件相關(guān)和硬件無(wú)關(guān)的代碼 劃分驅(qū)動(dòng)程序的抽象層次,Linux驅(qū)動(dòng)程序開(kāi)發(fā)的任務(wù),移植驅(qū)動(dòng)程序到新的平臺(tái),GPL對(duì)驅(qū)動(dòng)程序開(kāi)發(fā)的影響,實(shí)現(xiàn)非GPL授權(quán)的方法模塊形 式動(dòng)態(tài)加載 驅(qū)動(dòng)程序可以以私有產(chǎn)權(quán)形式進(jìn)行 商業(yè)

16、授權(quán),設(shè)備驅(qū)動(dòng)程序的代碼,驅(qū)動(dòng)程序的注冊(cè)與注銷(xiāo) register_chrdev() register_blkdev() 設(shè)備的打開(kāi)與釋放 open() release() 設(shè)備的讀寫(xiě)操作 read() write() 設(shè)備的控制操作 ioctl(,設(shè)備驅(qū)動(dòng)的加載,使用模塊的方式動(dòng)態(tài)加載驅(qū)動(dòng) int func_init(void) Makefile: insmod xx.o lsmod rmmod xx.o 將驅(qū)動(dòng)靜態(tài)編譯到內(nèi)核里面 int _init func_init(void) Makefile: 啟動(dòng)時(shí)自動(dòng)加載,Linux驅(qū)動(dòng)程序模塊加載,編寫(xiě)驅(qū)動(dòng)程序的一些基本概念,無(wú)論是什么操作系統(tǒng)的

17、驅(qū)動(dòng)程序,都有一些通用的概念 操作系統(tǒng)提供給驅(qū)動(dòng)程序的支持也大致相同 以下簡(jiǎn)單介紹網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)程序的一些基本要求,編寫(xiě)網(wǎng)絡(luò)驅(qū)動(dòng)程序,發(fā)送和接收 這是一個(gè)網(wǎng)絡(luò)設(shè)備最基本的功能 如一塊網(wǎng)卡所做的無(wú)非就是收發(fā)工作。所以驅(qū)動(dòng)程序里要告訴系統(tǒng)發(fā)送函數(shù)在哪里,系統(tǒng)在有數(shù)據(jù)要發(fā)送時(shí)就會(huì)調(diào)用發(fā)送程序。 驅(qū)動(dòng)程序由于是直接操縱硬件的,所以網(wǎng)絡(luò)硬件有數(shù)據(jù)收到,最先能得到這個(gè)數(shù)據(jù)的也就是驅(qū)動(dòng)程序,它負(fù)責(zé)把這些原始數(shù)據(jù)進(jìn)行必要的處理,然后送給系統(tǒng)。 這里,操作系統(tǒng)必須要提供兩個(gè)機(jī)制: 找到驅(qū)動(dòng)程序的發(fā)送函數(shù) 驅(qū)動(dòng)程序把收到的數(shù)據(jù)送給系統(tǒng),編寫(xiě)驅(qū)動(dòng)程序,讀寫(xiě) 幾乎所有設(shè)備都有輸入和輸出。每個(gè)驅(qū)動(dòng)程序要負(fù)責(zé)本設(shè)備的讀寫(xiě)操

18、作。 操作系統(tǒng)不需要知道對(duì)設(shè)備的具體讀寫(xiě)操作怎樣進(jìn)行,這些都由驅(qū)動(dòng)程序屏蔽掉了 操作系統(tǒng)定義好一些讀寫(xiě)接口,由驅(qū)動(dòng)程序完成具體的功能 在驅(qū)動(dòng)程序初始化時(shí),需要把具有這種接口的讀寫(xiě)函數(shù)注冊(cè)進(jìn)操作系統(tǒng),編寫(xiě)驅(qū)動(dòng)程序,中斷 中斷在現(xiàn)代計(jì)算機(jī)結(jié)構(gòu)中有重要的地位 操作系統(tǒng)必須提供驅(qū)動(dòng)程序響應(yīng)中斷的能力 一般是把一個(gè)中斷處理程序注冊(cè)到系統(tǒng)中去 操作系統(tǒng)在硬件中斷發(fā)生后調(diào)用驅(qū)動(dòng)程序的處理程序 Linux支持中斷的共享,即多個(gè)設(shè)備共享一個(gè)中斷,編寫(xiě)驅(qū)動(dòng)程序,時(shí)鐘 在實(shí)現(xiàn)驅(qū)動(dòng)程序時(shí),很多地方會(huì)用到時(shí)鐘。如某些協(xié)議里的超時(shí)處理,沒(méi)有中斷機(jī)制的硬件的輪詢等。 操作系統(tǒng)應(yīng)為驅(qū)動(dòng)程序提供定時(shí)機(jī)制 一般是在預(yù)定的時(shí)間過(guò)了

19、以后回調(diào)注冊(cè)的時(shí)鐘函數(shù),內(nèi)核模塊,模塊是內(nèi)核的一部分,但是并沒(méi)有被編譯到內(nèi)核里去。它們被分別編譯和連接成目標(biāo)文件。 用命令insmod插入一個(gè)模塊到內(nèi)核中,用命令rmmod卸載一個(gè)模塊 在Linux內(nèi)核中,以下內(nèi)容一般編譯成模塊: 大多數(shù)的驅(qū)動(dòng)程序。包括SCSI設(shè)備,CD-ROM,網(wǎng)絡(luò)設(shè)備,不常用的字符設(shè)備,如打印機(jī),watchdog等。 大多數(shù)文件系統(tǒng),理論上除了根文件系統(tǒng)不能是模塊,其他文件系統(tǒng)都可以是模塊。 一些內(nèi)核支持的不常用的可執(zhí)行文件格式,如binfmt_misc,kmod 和高級(jí)模塊化,Linux 提供了對(duì)模塊自動(dòng)加載和卸載的支持 要利用這一特性,在編譯內(nèi)核前進(jìn)行的配置中,必須打

20、開(kāi)對(duì) kmod 的支持選項(xiàng)。 一旦內(nèi)核試圖訪問(wèn)某種資源并發(fā)現(xiàn)該資源不可用時(shí),它會(huì)對(duì) kmod 子系統(tǒng)進(jìn)行一次特殊的調(diào)用而不僅僅是返回一個(gè)錯(cuò)誤 按需加載的例子 :ALSA(Advanced Linux Sound Architecture)聲卡驅(qū)動(dòng)程序組的實(shí)現(xiàn),常用的系統(tǒng)支持,內(nèi)存申請(qǐng)和釋放 中斷 時(shí)鐘 I/O 中斷打開(kāi)關(guān)閉 輸出信息 注冊(cè)驅(qū)動(dòng)程序,內(nèi)存申請(qǐng)和釋放,include/linux/kernel.h里聲明了kmalloc()和kfree()。用于在內(nèi)核模式下申請(qǐng)和釋放內(nèi)存。 與用戶模式下的malloc()不同,kmalloc()申請(qǐng)空間有大小限制。長(zhǎng)度是2的整次方。可以申請(qǐng)的最大長(zhǎng)度也

21、有限制。另外kmalloc()有priority參數(shù) Kfree()釋放的內(nèi)存必須是kmalloc()申請(qǐng)的,申請(qǐng)中斷和釋放中斷,request_irq()、free_irq() 是驅(qū)動(dòng)程序申請(qǐng)中斷和釋放中斷的調(diào)用。 在include/linux/sched.h里聲明,時(shí)鐘,時(shí)鐘的處理類(lèi)似中斷,也是登記一個(gè)時(shí)間處理函數(shù),在預(yù)定的時(shí)間過(guò)后,系統(tǒng)會(huì)調(diào)用這個(gè)函數(shù)。 在include/linux/timer.h里聲明 使用時(shí)鐘,先聲明一個(gè)timer_list結(jié)構(gòu),調(diào)用init_timer對(duì)它進(jìn)行初始化。Time_list結(jié)構(gòu)里expires是標(biāo)明這個(gè)時(shí)鐘的周期,單位采用jiffies的單位,I/O,I

22、/O端口的存取使用: inline unsigned int inb(unsigned short port); inline unsigned int inb_p(unsigned short port); inline void outb(char value, unsigned short port); inline void outb_p(char value, unsigned short port); 在include/adm/io.h里定義,中斷打開(kāi)關(guān)閉,系統(tǒng)提供給驅(qū)動(dòng)程序開(kāi)放和關(guān)閉響應(yīng)中斷的能力 是在include/asm/system.h #define cli() _asm

23、_ _volatile_ (cli:) #define sti() _asm_ _volatile_ (sti:,輸出信息,驅(qū)動(dòng)程序要輸出信息使用printk() include/linux/kernel.h里聲明,注冊(cè)驅(qū)動(dòng)程序,如果使用模塊(module)方式加載驅(qū)動(dòng)程序,需要在模塊初始化時(shí)把設(shè)備注冊(cè)到系統(tǒng)設(shè)備表里去 不再使用時(shí),把設(shè)備從系統(tǒng)中卸除 定義在drivers/net/net_init.h里的兩個(gè)函數(shù)完成這個(gè)工作 Int register_netdev(struct device *dev); void unregister_netdev(struct device *dev,網(wǎng)絡(luò)

24、驅(qū)動(dòng)程序的結(jié)構(gòu),所有的Linux網(wǎng)絡(luò)驅(qū)動(dòng)程序遵循通用的接口 設(shè)計(jì)時(shí)采用的是面向?qū)ο蟮姆椒?一個(gè)設(shè)備就是一個(gè)對(duì)象(device 結(jié)構(gòu)),它內(nèi)部有自己的數(shù)據(jù)和方法 每一個(gè)設(shè)備的方法被調(diào)用時(shí)的第一個(gè)參數(shù)都是這個(gè)設(shè)備對(duì)象本身。這樣這個(gè)方法就可以存取自身的數(shù)據(jù)(類(lèi)似面向?qū)ο蟪绦蛟O(shè)計(jì)時(shí)的this引用) 一個(gè)網(wǎng)絡(luò)設(shè)備最基本的方法有初始化、發(fā)送和接收,網(wǎng)絡(luò)驅(qū)動(dòng)程序的結(jié)構(gòu)(續(xù),初始化程序完成硬件的初始化、device中變量的初始化和系統(tǒng)資源的申請(qǐng) 發(fā)送程序是在驅(qū)動(dòng)程序的上層協(xié)議層有數(shù)據(jù)要發(fā)送時(shí)自動(dòng)調(diào)用的。一般驅(qū)動(dòng)程序中不對(duì)發(fā)送數(shù)據(jù)進(jìn)行緩存,而是直接使用硬件的發(fā)送功能把數(shù)據(jù)發(fā)送出去 接收數(shù)據(jù)一般是通過(guò)硬件中斷來(lái)通

25、知的。在中斷處理程序里,把硬件幀信息填入一個(gè)skbuff結(jié)構(gòu)中,然后調(diào)用netif_rx( )傳遞給上層處理,網(wǎng)絡(luò)驅(qū)動(dòng)程序的基本方法,初始化(initialize) 打開(kāi)(open) 關(guān)閉(stop ) 發(fā)送(hard_start_xmit) 接收(reception) 硬件幀頭(hard_header) 地址解析(xarp) 參數(shù)設(shè)置和統(tǒng)計(jì)數(shù)據(jù),網(wǎng)絡(luò)驅(qū)動(dòng)程序的基本方法-初始化,驅(qū)動(dòng)程序必須有一個(gè)初始化方法 在把驅(qū)動(dòng)程序載入系統(tǒng)的時(shí)候會(huì)調(diào)用這個(gè)初始化程序。它做以下幾方面的工作: 檢測(cè)設(shè)備:在初始化程序里你可以根據(jù)硬件的特征檢查硬件是否存在,然后決定是否啟動(dòng)這個(gè)驅(qū)動(dòng)程序。 配置和初始化硬件:在初

26、始化程序里可以完成對(duì)硬件資源的配置,比如即插即用的硬件就可以在這個(gè)時(shí)候進(jìn)行配置(Linux內(nèi)核對(duì)PnP功能沒(méi)有很好的支持,可以在驅(qū)動(dòng)程序里完成這個(gè)功能)。 配置或協(xié)商好硬件占用的資源以后,就可以向系統(tǒng)申請(qǐng)這些資源。有些資源是可以和別的設(shè)備共享的,如中斷。有些是不能共享的,如IO、DMA。 初始化device結(jié)構(gòu)中的變量 讓硬件正式開(kāi)始工作,網(wǎng)絡(luò)驅(qū)動(dòng)程序的基本方法打開(kāi),打開(kāi)(open) open這個(gè)方法在網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)程序里是在網(wǎng)絡(luò)設(shè)備被激活的時(shí)候被調(diào)用(即設(shè)備狀態(tài)由down-up) 實(shí)際上很多在initialize中的工作可以放到這里來(lái)做。比如資源的申請(qǐng)、硬件的激活。 如果dev-open返回非

27、0(error),則硬件的狀態(tài)還是down open方法另一個(gè)作用是如果驅(qū)動(dòng)程序做為一個(gè)模塊被裝入,則要防止模塊卸載時(shí)設(shè)備處于打開(kāi)狀態(tài)。 在open方法里要調(diào)用MOD_INC_USE_COUNT宏,網(wǎng)絡(luò)驅(qū)動(dòng)程序的基本方法關(guān)閉,關(guān)閉(stop) close方法做和open相反的工作??梢葬尫拍承┵Y源以減少系統(tǒng)負(fù)擔(dān)。 close是在設(shè)備狀態(tài)由up轉(zhuǎn)為down時(shí)被調(diào)用的 如果是做為模塊裝入的驅(qū)動(dòng)程序,close里 應(yīng)該調(diào)用MOD_DEC_USE_COUNT,減少設(shè)備被引用的次數(shù),以使驅(qū)動(dòng)程序可以被卸載。 close方法必須返回成功(0=success,網(wǎng)絡(luò)驅(qū)動(dòng)程序的基本方法發(fā)送,發(fā)送(hard_st

28、art_xmit) 所有的網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)程序都必須有這個(gè)發(fā)送方法。 在系統(tǒng)調(diào)用驅(qū)動(dòng)程序的xmit時(shí),發(fā)送的數(shù)據(jù)放在一個(gè)sk_buff結(jié)構(gòu)中。 一般的驅(qū)動(dòng)程序把數(shù)據(jù)傳給硬件發(fā)出去。也有一些特殊的設(shè)備比如loopback把數(shù)據(jù)組成一個(gè)接收數(shù)據(jù)再回送給系統(tǒng),或者 dummy設(shè)備直接丟棄數(shù)據(jù)。 如果發(fā)送成功,hard_start_xmit方法里釋放sk_buff,返回0(發(fā)送成功) 如果設(shè)備暫時(shí)無(wú)法處理,比如硬件忙,則返回1。這時(shí)如果dev-tbusy置為非0,則系統(tǒng)認(rèn)為硬件忙,要等到dev-tbusy置0以后才會(huì)再次發(fā)送。tbusy的置0任務(wù)一般由中斷完成,網(wǎng)絡(luò)驅(qū)動(dòng)程序的基本方法發(fā)送(續(xù),硬件在發(fā)送結(jié)

29、束后產(chǎn)生中斷,這時(shí)可以把tbusy置0,然后用mark_bh()調(diào)用通知系統(tǒng)可以再次發(fā)送。 在發(fā)送不成功的情況下,也可以不置dev-tbusy為非0,這樣系統(tǒng)會(huì)不斷嘗試重發(fā)。 如果hard_start_xmit發(fā)送不成功,則不要釋放sk_buff。 傳送下來(lái)的sk_buff中的數(shù)據(jù)已經(jīng)包含硬件需要的幀頭。所以在發(fā)送方法里不需要再填充硬件幀頭,數(shù)據(jù)可以直接提交給硬件發(fā)送。sk_buff是被鎖住的(locked), 確保其他程序不會(huì)存取它,網(wǎng)絡(luò)驅(qū)動(dòng)程序的基本方法接收,接收(reception) 驅(qū)動(dòng)程序并不存在一個(gè)接收方法。有數(shù)據(jù)收到應(yīng)該是驅(qū)動(dòng)程序來(lái)通知系統(tǒng)的。 一般設(shè)備收到數(shù)據(jù)后都會(huì)產(chǎn)生一個(gè)中斷

30、,在中斷處理程序中驅(qū)動(dòng)程序申請(qǐng)一塊sk_buff(skb),從硬件讀出數(shù)據(jù)放置到申請(qǐng)好的緩沖區(qū)里。接下來(lái)填充sk_buff中的一些信息。skb-dev = dev,判斷收到幀的協(xié)議類(lèi)型,填入skb-protocol(多協(xié) 議的支持)。 把指針skb-mac.raw指向硬件數(shù)據(jù)然后丟棄硬件幀頭(skb_pull,網(wǎng)絡(luò)驅(qū)動(dòng)程序的基本方法接收(續(xù),還要 設(shè)置skb-pkt_type,標(biāo)明第二層(鏈路層)數(shù)據(jù)類(lèi)型??梢允且韵骂?lèi)型: PACKET_BROADCAST : 鏈路層廣播 PACKET_MULTICAST : 鏈路層組播 PACKET_SELF : 發(fā)給自己的幀 PACKET_OTHERHOS

31、T : 發(fā)給別人的幀(監(jiān)聽(tīng)模式時(shí)會(huì)有這種幀) 最后調(diào)用netif_rx()把數(shù)據(jù)傳送給協(xié)議層。netif_rx()里數(shù)據(jù)放入處理隊(duì)列然后返回,真正的處理是在中斷返回以后,這樣可以減少中斷時(shí)間。 調(diào)用netif_rx()以后,驅(qū)動(dòng)程序就不能再存取數(shù)據(jù)緩沖區(qū)skb,網(wǎng)絡(luò)驅(qū)動(dòng)程序的基本方法硬件幀頭,硬件一般都會(huì)在上層數(shù)據(jù)發(fā)送之前加上自己的硬件幀頭,比如以太網(wǎng)(Ethernet)就有14字節(jié)的幀頭。這個(gè)幀頭是加在上層ip、ipx等數(shù)據(jù)包的前面的。 驅(qū)動(dòng)程序提供一個(gè)hard_header方法,協(xié)議層(ip、ipx、arp等)在發(fā)送數(shù)據(jù)之前會(huì)調(diào)用這段程序。 硬件幀頭的長(zhǎng)度必須填在dev-hard_head

32、er_len,這樣協(xié)議層回在數(shù)據(jù)之前保留好硬件幀頭的空間。這樣hard_header程序只要調(diào)用skb_push然后正確填入硬件幀頭就可以了,網(wǎng)絡(luò)驅(qū)動(dòng)程序的基本方法硬件幀頭(續(xù)1,在協(xié)議層調(diào)用hard_header時(shí),傳送的參數(shù)包括(2.0.xx): 數(shù)據(jù)的sk_buff device指針 Protocol 目的地址(daddr) 源地址(saddr) 數(shù)據(jù)長(zhǎng)度(len) 數(shù)據(jù)長(zhǎng)度不要使用sk_buff中的參數(shù),因?yàn)檎{(diào)用hard_header時(shí)數(shù)據(jù)可能還沒(méi)完全組織好 saddr是NULL的話是使用缺省地址(default) daddr是NULL表明協(xié)議層不知道硬件目的地址 如果hard_hea

33、der完全填好了硬件幀頭,則返回添加的字節(jié)數(shù),網(wǎng)絡(luò)驅(qū)動(dòng)程序的基本方法硬件幀頭(續(xù)2,如果硬件幀頭中的信息還不完全(比如daddr為NULL,但是幀頭中需要目的硬件地址。典型的情況是以太網(wǎng)需要地址解析(arp),則返回負(fù)字節(jié)數(shù)。hard_header返回負(fù)數(shù)的情況下,協(xié)議層會(huì)做進(jìn)一步的build header的工作。 目前Linux系統(tǒng)里就是做arp (如果hard_header返回正,dev-arp=1,表明不需要做arp,返回負(fù),dev-arp=0,做arp)。 對(duì)hard_header的調(diào)用在每個(gè)協(xié)議層的處理程序里。如ip_output,網(wǎng)絡(luò)驅(qū)動(dòng)程序的基本方法地址解析,地址解析(xarp)

34、 有些網(wǎng)絡(luò)有硬件地址(比如Ethernet),并且在發(fā)送硬件幀時(shí)需要知道目的硬件地址。這樣就需要上層協(xié)議地址(ip、ipx)和硬件地址的對(duì)應(yīng)。這個(gè)對(duì)應(yīng)是通過(guò)地址 解析完成的。 需要做arp的的設(shè)備在發(fā)送之前會(huì)調(diào)用驅(qū)動(dòng)程序的rebuild_header方法。調(diào)用的主要參數(shù)包括: 指向硬件幀頭的指針 協(xié)議層地址 如果驅(qū)動(dòng)程序能夠解析硬件地址,就返回1,如果不能,返回0。 對(duì)rebuild_header的調(diào)用在net/core/dev.c的do_dev_queue_xmit()里,網(wǎng)絡(luò)驅(qū)動(dòng)程序的基本方法參數(shù)設(shè)置和統(tǒng)計(jì)數(shù)據(jù),參數(shù)設(shè)置和統(tǒng)計(jì)數(shù)據(jù) 在驅(qū)動(dòng)程序里還提供一些方法供系統(tǒng)對(duì)設(shè)備的參數(shù)進(jìn)行設(shè)置和讀取

35、信息。 一般只有超級(jí)用戶(root)權(quán)限才能對(duì)設(shè)備參數(shù)進(jìn)行設(shè)置。 設(shè)置方法有: dev-set_mac_address() 當(dāng)用戶調(diào)用ioctl類(lèi)型為SIOCSIFHWADDR時(shí)是要設(shè)置這個(gè)設(shè)備的mac地址。一般對(duì)mac地址的設(shè)置沒(méi)有太大意義的,網(wǎng)絡(luò)驅(qū)動(dòng)程序的基本方法參數(shù)設(shè)置和統(tǒng)計(jì)數(shù)據(jù)(續(xù),dev-set_config() 當(dāng)用戶調(diào)用ioctl時(shí)類(lèi)型為SIOCSIFMAP時(shí),系統(tǒng)會(huì)調(diào)用驅(qū)動(dòng)程序的set_config方法。用戶會(huì)傳遞一個(gè)ifmap結(jié)構(gòu)包含需要的I/O、中斷等參數(shù)。 dev-do_ioctl() 如果用戶調(diào)用ioctl時(shí)類(lèi)型在SIOCDEVPRIVATE和SIOCDEVPRIVAT

36、E+15之間,系統(tǒng)會(huì)調(diào)用驅(qū)動(dòng)程序的這個(gè)方法。一般是設(shè)置設(shè)備的專用數(shù)據(jù)。 讀取信息也是通過(guò)ioctl調(diào)用進(jìn)行。 除次之外驅(qū)動(dòng)程序還可以提供一個(gè)dev-get_stats方法,返回一個(gè)enet_statistics結(jié)構(gòu),包含發(fā)送接收的統(tǒng)計(jì)信息。 ioctl的處理在net/core/dev.c的dev_ioctl()和dev_ifsioc()里,網(wǎng)絡(luò)驅(qū)動(dòng)程序中用到的數(shù)據(jù)結(jié)構(gòu),最重要的是網(wǎng)絡(luò)設(shè)備的數(shù)據(jù)結(jié)構(gòu)。它定義在include/linux/netdevice.h sk_buff Linux網(wǎng)絡(luò)各層之間的數(shù)據(jù)傳送都是通過(guò)sk_buff,編寫(xiě)Linux網(wǎng)絡(luò)驅(qū)動(dòng)程序中需要注意的問(wèn)題,中斷共享 硬件發(fā)送忙時(shí)

37、的處理 流量控制(flow control) 調(diào)試,中斷共享,Linux系統(tǒng)運(yùn)行幾個(gè)設(shè)備共享同一個(gè)中斷。需要共享的話,在申請(qǐng)的時(shí)候指明共享方式。 系統(tǒng)提供的request_irq()調(diào)用的定義: int request_irq(unsigned int irq, void (*handler)(int irq, void *dev_id, struct pt_regs *regs), unsigned long irqflags, const char * devname, void *dev_id); 如果共享中斷,irqflags設(shè)置SA_SHIRQ屬性,這樣就允許別的設(shè)備申請(qǐng)同一個(gè)中斷。

38、需要注意所有用到這個(gè)中斷的設(shè)備在調(diào)用request_irq()都必須設(shè)置這個(gè)屬性。系統(tǒng)在回調(diào)每個(gè)中斷處理程序時(shí),可以用dev_id這個(gè)參數(shù)找到相應(yīng)的設(shè)備。一 般dev_id就設(shè)為device結(jié)構(gòu)本身。系統(tǒng)處理共享中斷是用各自的dev_id參數(shù)依次調(diào)用每一個(gè)中斷處理程序,硬件發(fā)送忙時(shí)的處理,主CPU的處理能力一般比網(wǎng)絡(luò)發(fā)送要快,所以經(jīng)常會(huì)遇到系統(tǒng)有數(shù)據(jù)要發(fā),但上一包數(shù)據(jù)網(wǎng)絡(luò)設(shè)備還沒(méi)發(fā)送完。因?yàn)樵贚inux里網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)程序一般不做數(shù)據(jù)緩存,不能發(fā)送的數(shù)據(jù)都是通知系統(tǒng)發(fā)送不成功,所以必須要有一個(gè)機(jī)制在硬件不忙時(shí)及時(shí)通知系統(tǒng)接著發(fā)送下面的數(shù)據(jù)。 一般對(duì)發(fā)送忙的處理在前面設(shè)備的發(fā)送方法(hard_st

39、art_xmit)里已經(jīng)描述過(guò),即如果發(fā)送忙,置tbusy為1。處理完發(fā)送數(shù)據(jù)后,在發(fā)送結(jié)束中斷里清tbusy,同時(shí)用mark_bh()調(diào)用通知系統(tǒng)繼續(xù)發(fā)送。 但在具體實(shí)現(xiàn)驅(qū)動(dòng)程序時(shí)發(fā)現(xiàn),這樣的處理系統(tǒng)好象并不能及時(shí)地知道硬件已經(jīng)空閑了,即在mark_bh()以后,系統(tǒng)要等一段時(shí)間才會(huì)接著發(fā)送。造成發(fā)送效率很低。 實(shí)現(xiàn)時(shí)不把tbusy置1,讓系統(tǒng)始終認(rèn)為硬件空閑,但是報(bào)告發(fā)送不成功。系統(tǒng)會(huì)一直嘗試重發(fā)。這樣處理就運(yùn)行正常了,流量控制,網(wǎng)絡(luò)數(shù)據(jù)的發(fā)送和接收都需要流量控制。這些控制是在系統(tǒng)里實(shí)現(xiàn)的,不需要驅(qū)動(dòng)程序做工作。 每個(gè)設(shè)備數(shù)據(jù)結(jié)構(gòu)里都有一個(gè)參數(shù)dev-tx_queue_len,這個(gè)參數(shù) 標(biāo)

40、明發(fā)送時(shí)最多緩存的數(shù)據(jù)包。在Linux系統(tǒng)里以太網(wǎng)設(shè)備(10/100Mbps) tx_queue_len一般設(shè)置為100,串行線路(異步串口)為10。 實(shí)際上,設(shè)置了dev-tx_queue_len并不是為緩存這些數(shù)據(jù)申請(qǐng)了空間。這個(gè)參數(shù)只是在收到協(xié)議層的數(shù)據(jù)包時(shí)判斷發(fā)送隊(duì)列里的數(shù)據(jù)是不是到了tx_queue_len的限度,以決定這一包數(shù)據(jù)加不加進(jìn)發(fā)送隊(duì)列。發(fā)送時(shí)另一個(gè)方面的流控是更高層協(xié)議的發(fā)送窗口(TCP協(xié)議里就有發(fā)送窗口)。 達(dá)到了窗口大小,高層協(xié)議就不會(huì)再發(fā)送數(shù)據(jù)。 接收流控也分兩個(gè)層次。netif_rx()緩存的數(shù)據(jù)包有限制。另外高層協(xié)議也會(huì)有一個(gè)最大的等待處理的數(shù)據(jù)量。 發(fā)送和接收

41、流控處理在net/core/dev.c的do_dev_queue_xmit()和netif_rx() 中,調(diào)試,很多Linux的驅(qū)動(dòng)程序都是編譯進(jìn)內(nèi)核的,形成一個(gè)大的內(nèi)核文件。但對(duì)調(diào)試來(lái)說(shuō),這是相當(dāng)麻煩的。調(diào)試驅(qū)動(dòng)程序可以用module方式加載。 支持模塊方式的驅(qū)動(dòng)程序必須提供兩個(gè)函數(shù):int init_module(void)和void cleanup_module(void)。 init_module()在加載此模塊時(shí)調(diào)用,在這個(gè)函數(shù)里可以register_netdev()注冊(cè)設(shè)備。init_module()返回0表示成功,返回負(fù)表示失敗。 cleanup_module()在驅(qū)動(dòng)程序被卸載

42、時(shí)調(diào)用,清除占用的資源,調(diào)用unregister_netdev()。 模塊可以動(dòng)態(tài)地加載、卸載。在2.0.xx版本里,還有kerneld自動(dòng)加載模塊,但是2.2.xx中已經(jīng)取消了kerneld。手工加載使用insmod命令,卸載用rmmod命令,看內(nèi)核中的模塊用lsmod命令。 編譯驅(qū)動(dòng)程序用gcc,主要命令行參數(shù)-DKERNEL -DMODULE。并且作為模塊加載的驅(qū)動(dòng)程序,只編譯成obj形式(加-c參數(shù))。編譯好的目標(biāo)文件放在/lib/modules/2.x.xx/misc下,在啟動(dòng)文件里用insmod加載,Linux驅(qū)動(dòng)程序可利用資源,互聯(lián)網(wǎng)上有很多驅(qū)動(dòng)程序資源: www.kernel.

43、org ,驅(qū)動(dòng)源代碼,驅(qū)動(dòng)源代碼,驅(qū)動(dòng)源代碼,驅(qū)動(dòng)源代碼,驅(qū)動(dòng)源代碼,編譯驅(qū)動(dòng)程序,應(yīng)用程序,編譯應(yīng)用程序,背景知識(shí): Linux設(shè)備管理,主要內(nèi)容,概述 驅(qū)動(dòng)程序基礎(chǔ) 中斷處理 輔助函數(shù) 設(shè)備驅(qū)動(dòng)程序 模塊編程基礎(chǔ) 字符設(shè)備 塊設(shè)備 網(wǎng)絡(luò)設(shè)備,概述,輸入輸出子系統(tǒng): 下層:設(shè)備驅(qū)動(dòng)程序 上層:設(shè)備無(wú)關(guān)部分VFS in Linux? Unix和Linux的設(shè)備管理方法: VFS,設(shè)備管理總體結(jié)構(gòu)示意,用戶程序,系統(tǒng)調(diào)用接口,文件系統(tǒng),高速緩存,字符設(shè)備,塊設(shè)備,驅(qū)動(dòng)程序,硬件設(shè)備,輸入輸出系統(tǒng)層次結(jié)構(gòu),用戶進(jìn)程,設(shè)備無(wú)關(guān)軟件,設(shè)備驅(qū)動(dòng)程序,設(shè)備服務(wù)子程序

44、,中斷處理程序,硬件,I/O請(qǐng)求,I/O應(yīng)答,進(jìn)行I/O調(diào)用;格式化I/O 命名、保護(hù)、阻塞、緩沖、分配 建立設(shè)備寄存器、檢測(cè)狀態(tài) I/O結(jié)束時(shí),喚醒設(shè)備服務(wù)子程序 執(zhí)行I/O操作,驅(qū)動(dòng)程序基礎(chǔ)I/O空間,Linux中的三種地址空間: CPU Untranslated Address CPU Translated Address Bus Address:一般PC機(jī)中是一組寄存器 命令more /proc/ioports 常見(jiàn)總線ISAVESAEISAPCI,驅(qū)動(dòng)程序基礎(chǔ)命名空間,并行設(shè)備:lp軟盤(pán):fdSCSI盤(pán):sdIDE硬盤(pán):hda1, hda2, hdb等網(wǎng)絡(luò)設(shè)備:ethn, slipn

45、, pppn等 在寫(xiě)驅(qū)動(dòng)程序的時(shí)候,需要給函數(shù)名加上選擇的前綴來(lái)避免任何混淆。如:foo_read(),foo_write()等,驅(qū)動(dòng)程序基礎(chǔ)內(nèi)存分配,函數(shù)kmalloc()內(nèi)存以2的冪大小的塊分配 有一個(gè)優(yōu)先級(jí)參數(shù) 宏kfree()和函數(shù)kfree_s()kfree()調(diào)用kfree_s(),和free()一樣工作可以直接調(diào)用kfree_s(),但是需要知道釋放內(nèi)存塊的大小,驅(qū)動(dòng)程序基礎(chǔ)設(shè)備分類(lèi),字符設(shè)備:不使用緩沖區(qū),順序讀寫(xiě)foo_read() struct wait_queue *next;,驅(qū)動(dòng)程序基礎(chǔ)設(shè)備文件,設(shè)備管理的“上半部分” Struct file結(jié)構(gòu)include/lin

46、ux/fs.h 增加一個(gè)設(shè)備時(shí)需要用mknod命令為該設(shè)備創(chuàng)建一個(gè)inode,驅(qū)動(dòng)程序基礎(chǔ)file_operations,lseek():轉(zhuǎn)到所需的偏移。 struct inode *inode 指向此設(shè)備inode結(jié)構(gòu)的指針。 Struct file *file 指向此設(shè)備的文件結(jié)構(gòu)的指針。 Off_t offset 要轉(zhuǎn)移到的相對(duì)origin指示的基準(zhǔn)的偏移地址。 Int origin 0 = 采用相對(duì)于絕對(duì)地址0(開(kāi)始)的偏移量。 1 = 采用相對(duì)于當(dāng)前位置的偏移量。 2 = 采用相對(duì)于末尾的偏移量。 Lseek()在出錯(cuò)是返回出錯(cuò)碼 errno,否則返回lseek操作以后的絕對(duì)地址(=

47、0,read()和write()struct inode *inode:指向代表要訪問(wèn)的設(shè)備的特殊文件的指針。sturct file *file:指向該設(shè)備的文件結(jié)構(gòu)的指針。 Char *buf:一個(gè)讀寫(xiě)的字符緩沖區(qū)。位于用戶空間內(nèi)存中,可以用get_fs*(),put_fs*()和memcpy*fs()訪問(wèn)。 Int count:緩沖區(qū)中讀或?qū)懙淖址挠?jì)數(shù)。它是buf的大小,也是知道怎樣到達(dá)buf的末尾的手段,因?yàn)閎uf是沒(méi)有保證以NULL結(jié)尾的,Select()struct inode *inode:指向該設(shè)備的inode結(jié)構(gòu)的指針。 Struct file *file:指向設(shè)備的文件結(jié)構(gòu)

48、的指針。 Int sel_type:可以執(zhí)行的選擇類(lèi)型 SEL_IN read SEL_OUT write SEL_EX exception Select_table *wait 如果設(shè)備沒(méi)有準(zhǔn)備好,調(diào)用select_wait(),并且返回0。 如果設(shè)備準(zhǔn)備好,返回1,ioctl()函數(shù):處理ioctl調(diào)用。 結(jié)構(gòu):首先差錯(cuò)檢查,然后用一個(gè)大的switch語(yǔ)句來(lái)處理所有可能的ioct。 參數(shù): Struct inode *inode Struct file *file Unsigned int cmd :ioctl命令。一般用于做case語(yǔ)句的switch參數(shù)。 Unsigned int ar

49、g 這是此命令的參數(shù),由用戶定義。 返回: 出錯(cuò)返回-error。 其他情況下返回由用戶定義,mmap()函數(shù) Struct inode *inode Struct file *file Unsigned long addr 需要映射進(jìn)入的主存開(kāi)始地址。 Size_t len 需要映射的存儲(chǔ)空間長(zhǎng)度。 Int prot 下面中的一個(gè): PROT_READ 可以讀的區(qū)域。 PROT_WRITE 可寫(xiě)的區(qū)域 PROT_EXEC 可執(zhí)行的區(qū)域 PROT_NONE 不可訪問(wèn)的區(qū)域 Unsigned long off 需要映射的文件偏移地址。這個(gè)地址將被映射到addr,open()和release()函

50、數(shù) Struct inode *inode 指向此設(shè)備的inode結(jié)構(gòu)的指針。 Struct file *file 指向此設(shè)備的文件結(jié)構(gòu)的指針。 Open()在設(shè)備特殊文件打開(kāi)時(shí)調(diào)用。是用來(lái)保證一致性的策略機(jī)制。 Release()只在進(jìn)程關(guān)閉它打開(kāi)的最后一個(gè)文件描述子的時(shí)候調(diào)用,init()函數(shù)內(nèi)核第一次啟動(dòng)時(shí)調(diào)用: 在正確的位置調(diào)用init(): 字符設(shè)備drivers/char/mem.c中的chr_dev_init() 把file_operation注冊(cè)到VFS中: 對(duì)于字符設(shè)備register_chrdev() 打印關(guān)于設(shè)備的信息,并且報(bào)告找到的硬件 printk(,中斷處理,文件/

51、proc/interrupts 函數(shù)request_irq() 函數(shù)free_irq() 睡眠與喚醒 中斷共享 ISR的上部和下部(bottomhalf,輔助函數(shù)請(qǐng)求調(diào)度,Static void add_request(struct blk_dev_struct *dev, struct request * req)Static void end_request(struct blk_dev_struct *dev, struct request * req)static void make_request(int major, int rw, struct buffer_head *bh)v

52、oid ll_rw_block(int rw, int nr, struct buffer_head *bh)make_request()調(diào)用add_request()ll_rw_block()對(duì)請(qǐng)求隊(duì)列排序,只能通過(guò)buffer cache調(diào)用。 電梯算法: 讀在寫(xiě)前 低次設(shè)備號(hào)請(qǐng)求在高次設(shè)備號(hào)前 低塊號(hào)在高塊號(hào)前 drivers/block/ll_rw_block.c,輔助函數(shù)定時(shí)器管理,void add_timer(struct timer_list * timer) void del_timer(struct timer_list * timer) void init_timer(st

53、ruct timer_list * timer) struct timer_list,輔助函數(shù)中斷管理,extern int request_irq(unsigned int irq, void (*handler)(int, void*, struct pt_regs *), unsigned long flags, const char *device, void *dev_id);void free_irq(unsigned int irq) cli()sti(,輔助函數(shù)端口讀寫(xiě),void out*() unsigned char byte, unsigned port unsigned

54、 in*() 參數(shù):unsigned port*: b, w, l 用in*()來(lái)清空某些狀態(tài)值,輔助函數(shù)內(nèi)存管理 void brelse(struct buffer_head *buf); void ll_rw_block(int rw, int nr, struct buffer_head*bh,輔助函數(shù)其他,int printk(const char* fmt, .)#include 在內(nèi)核中打印信息,是printf的內(nèi)核版本 可能導(dǎo)致隱含的I/O操作。不要在cli()保護(hù)的代碼段中使用,因?yàn)樗赡軐?dǎo)致開(kāi)中斷。 一些與進(jìn)程相關(guān)的系統(tǒng)調(diào)用,模塊編程基礎(chǔ),模塊的基本概念: 可以動(dòng)態(tài)的加載到內(nèi)

55、核中成為kernel的一部分;加載后可以訪問(wèn)內(nèi)核的數(shù)據(jù)結(jié)構(gòu); 用戶空間的程序或進(jìn)程可以通過(guò)某個(gè)模塊和內(nèi)核交互。 module在需要的時(shí)可通過(guò)符號(hào)表(symbol table)使用核心資源。 而且module一般需要調(diào)用核心的資源,所以必須注意module的版本和核心的版本的相配問(wèn)題。一般在module的裝入過(guò)程中檢查module的版本信息,模塊之間的函數(shù)調(diào)用 內(nèi)核可以使用其它模塊或內(nèi)核的函數(shù),也可以export一些函數(shù)供其他模塊或內(nèi)核使用。 模塊棧:如果模塊A使用了模塊B的函數(shù),那么B必須在A之前加載,否則加載A的命令不成功。 模塊可以使用的函數(shù): 自身定義; 其他module提供; 內(nèi)核提供

56、 命令ksyms a:列出已經(jīng)加載的模塊的函數(shù)或變量。 Symbol table:記錄module導(dǎo)出的函數(shù)或變量。 所有聲明為global的函數(shù)或變量都意味著被導(dǎo)出,可以被其他模塊使用,模塊編程基礎(chǔ)常用命令,lsmod 把現(xiàn)在 kernel 中已經(jīng)安裝的modules 列出來(lái) insmod 把某個(gè) module 安裝到 kernel 中。 rmmod 把某個(gè)沒(méi)在用的 module 從kerne中卸載。 depmod 制造 module dependency file,以告訴將來(lái)的 insmod 要去哪兒找modules 來(lái)安裝。這個(gè) dependency file放在 /lib/module

57、s/當(dāng)前kernel版本/modules.dep,模塊基礎(chǔ)裝入,Insmod命令 內(nèi)核kerneld守護(hù)進(jìn)程(daemon)自動(dòng)裝入。守護(hù)進(jìn)程:在超級(jí)用戶下運(yùn)行的一個(gè)用戶進(jìn)程,與核心建立一個(gè)IPC通道。Kerneld調(diào)用insmod和rmmond來(lái)裝入和移出模塊。kerneld裝入的module,一般放在/lib/modules/kernel-version目錄下。 insmod 命令調(diào)用sys_get_kernel_sys()系統(tǒng)調(diào)用收集核心中所有符號(hào)來(lái)解決module中資源引用問(wèn)題,模塊基礎(chǔ)裝入,符號(hào)表的記錄有兩個(gè)域:符號(hào)的名字(symbol name)和符號(hào)的值(一般是符號(hào)的地址)。核心

58、提供的符號(hào)表在module 鏈表最尾module中。 insmod調(diào)用sys_create_module(),為新module分配一個(gè)module數(shù)據(jù)結(jié)構(gòu),掛在module_list頭上,置新module 狀態(tài)為UNINITIALIZED。 當(dāng)初始化module時(shí),insmod調(diào)用sys_init_module()系統(tǒng)調(diào)用,將module的初始化和清除函數(shù)作為參數(shù)傳遞。修改核心的符號(hào)表,同時(shí)系統(tǒng)需要修改新module依賴的所有module中的相關(guān)指針,模塊基礎(chǔ)卸載,Rmmod命令 Kerneld進(jìn)程自動(dòng)卸載自動(dòng)卸載的機(jī)制為:每隔一定的時(shí)間,kerneld 調(diào)用sys_delete_module

59、()系統(tǒng)調(diào)用,將它裝入的且不在被使用的module從系統(tǒng)中卸載。它遍歷module_list,檢查被它裝入(AUTOCLEAN)并且不用(VISITED標(biāo)志)的模塊,內(nèi)核模塊必須有兩個(gè)函數(shù): int init_module():為內(nèi)核中的某些東西注冊(cè)一個(gè)句柄,或者把內(nèi)核中的程序提換成它自己的代碼(通常是進(jìn)行一些工作以后再調(diào)用原來(lái)工作的代碼)。 void clean_module():模塊要求撤銷(xiāo)init_module進(jìn)行的所有修改,使得模塊可以被安全的卸載。 在insmod和rmmod命令中使用這兩個(gè)函數(shù)。 Use count:記錄使用本模塊的進(jìn)程數(shù)或模塊數(shù)。 MOD_INC_USE_COUNT:增加use count MOD_DEC_USE_COUNT:減少u(mài)se count MOD_IN_USE:檢查use count是否是0,模塊基礎(chǔ)數(shù)據(jù)結(jié)構(gòu),struct module struct module *next; struct module_ref *ref;/* 所有引用該模塊的模塊,也用鏈表連接*/ struct symbol_table *symtab; /*符號(hào)表*/ const char *name; /*模塊的名字,存放在module結(jié)構(gòu)后面的64個(gè)字節(jié)里 */ int size;/* size of module in pages */ vo

溫馨提示

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

評(píng)論

0/150

提交評(píng)論