![Linux系統(tǒng)的硬件驅(qū)動程序編寫原理_第1頁](http://file3.renrendoc.com/fileroot_temp3/2022-1/17/fe08faa3-4a78-4f5d-999a-01515e0078e9/fe08faa3-4a78-4f5d-999a-01515e0078e91.gif)
![Linux系統(tǒng)的硬件驅(qū)動程序編寫原理_第2頁](http://file3.renrendoc.com/fileroot_temp3/2022-1/17/fe08faa3-4a78-4f5d-999a-01515e0078e9/fe08faa3-4a78-4f5d-999a-01515e0078e92.gif)
![Linux系統(tǒng)的硬件驅(qū)動程序編寫原理_第3頁](http://file3.renrendoc.com/fileroot_temp3/2022-1/17/fe08faa3-4a78-4f5d-999a-01515e0078e9/fe08faa3-4a78-4f5d-999a-01515e0078e93.gif)
![Linux系統(tǒng)的硬件驅(qū)動程序編寫原理_第4頁](http://file3.renrendoc.com/fileroot_temp3/2022-1/17/fe08faa3-4a78-4f5d-999a-01515e0078e9/fe08faa3-4a78-4f5d-999a-01515e0078e94.gif)
![Linux系統(tǒng)的硬件驅(qū)動程序編寫原理_第5頁](http://file3.renrendoc.com/fileroot_temp3/2022-1/17/fe08faa3-4a78-4f5d-999a-01515e0078e9/fe08faa3-4a78-4f5d-999a-01515e0078e95.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、Linux系統(tǒng)的硬件驅(qū)動程序編寫原理*本文詳細地介紹如何Linux系統(tǒng)的硬件驅(qū)動程序的編寫原理,指出哪些內(nèi)核例程將會被調(diào)用、如何初始化驅(qū)動程序及如何分配內(nèi)存等等。大家一定對Linux操作系統(tǒng)有所了解了,在此本人也不再贅述了。好吧,下面簡單地介紹一下設(shè)備驅(qū)動程序。顧名思義,驅(qū)動程序是用來控制計算機外圍設(shè)備的,Linux系統(tǒng)將所有的外圍設(shè)備都高度地抽象成一些字節(jié)的序列,并且以文件的形式來表示這些設(shè)備。我們可以來看一下Linux的I/O子系統(tǒng)(圖1)。圖1 Linux的I/O子系統(tǒng)從圖上我們可以看出,內(nèi)核緊緊地包圍在硬件周圍,內(nèi)核是一些軟件包的組合,它們可以直接訪問系統(tǒng)的硬件,包括處理器、內(nèi)存和I/
2、O設(shè)備。而用戶進程則通過內(nèi)核提供的用戶服務(wù)來和內(nèi)核通訊,從而間接地控制系統(tǒng)硬件。我們可以通過圖2來了解這些動作的具體情況。 圖2 用戶級、內(nèi)核級和硬件級三者之間的通訊圖上顯示了用戶級的程序使用內(nèi)核提供的標準系統(tǒng)調(diào)用來與內(nèi)核通訊,這些系統(tǒng)調(diào)用有:open(), read(), write(), ioctl(), close() 等等。Linux的內(nèi)核是一個有機的整體。每一個用戶進程運行時都好像有一份內(nèi)核的拷貝,每當用戶進程使用系統(tǒng)調(diào)用時,都自動地將運行模式從用戶級轉(zhuǎn)為內(nèi)核級,此時進程在內(nèi)核的地址空間中運行。圖3 Linux的I/O子系統(tǒng)Linux內(nèi)核使用"設(shè)備無關(guān)"的I/O子
3、系統(tǒng)來為所有的設(shè)備服務(wù)。每個設(shè)備都提供標準接口給內(nèi)核,從而盡可能地隱藏了自己的特性。圖3展示了用戶程序使用一些基本的系統(tǒng)調(diào)用從設(shè)備讀取數(shù)據(jù)并且將它們存入緩沖的例子。我們可以看到,每當一個系統(tǒng)調(diào)用被使用時,內(nèi)核就轉(zhuǎn)到相應(yīng)的設(shè)備驅(qū)動例程來操縱硬件。每個設(shè)備在Linux系統(tǒng)上看起來都像一個文件,它們存放在/dev目錄中并被稱為"特殊文件"或是"設(shè)備節(jié)點"。大家可以使用ls -l /dev/lp* 來得到以下的輸出: crw-rw-rw 1 root root 6, 0 April 23 1994 /dev/lp0 這行輸出表示lp0是一個字符設(shè)備(屬性字段的第
4、一個字符是'c'),主設(shè)備號是6,次設(shè)備號是0。主設(shè)備號用來向內(nèi)核表明這一設(shè)備節(jié)點所代表的驅(qū)動程序的類型(比如:主設(shè)備號是3的塊設(shè)備是IDE磁盤驅(qū)動程序,而主設(shè)備號為8的塊設(shè)備是SCSI磁盤驅(qū)動程序);每個驅(qū)動程序負責管理它所驅(qū)動的幾個硬件實例,這些硬件實例則由次設(shè)備號來表示(例如:次設(shè)備號為0的SCSI磁盤代表整個也可以說是"第一個"SCSI磁盤,而次設(shè)備號為1到15的磁盤代表此SCSI磁盤上的15個分區(qū))。到此大家應(yīng)該對Linux的設(shè)備有所了解了吧,下面就可以開始我們的正題"設(shè)備驅(qū)動程序"。設(shè)備驅(qū)動程序是一組由內(nèi)核中的相關(guān)子例程和數(shù)據(jù)
5、組成的I/O設(shè)備軟件接口。每當內(nèi)核意識到要對某個設(shè)備進行特殊的操作時,它就調(diào)用相應(yīng)的驅(qū)動例程。這就使得控制從用戶進程轉(zhuǎn)移到了驅(qū)動例程,當驅(qū)動例程完成后,控制又被返回至用戶進程。圖5就顯示了以上的過程。圖5 設(shè)備驅(qū)動程序的作用每個設(shè)備驅(qū)動程序都具有以下幾個特性:l 具有一整套的和硬件設(shè)備通訊的例程,并且提供給操作系統(tǒng)一套標準的軟件接口;l 具有一個可以被操作系統(tǒng)動態(tài)地調(diào)用和移除的自包含組件;l 可以控制和管理用戶程序和物理設(shè)備之間的數(shù)據(jù)流。接下來我們來了解一下字符設(shè)備和塊設(shè)備,它們是Linux系統(tǒng)中兩種主要的外圍設(shè)備。我們常見的磁盤是塊設(shè)備,而終端和打印機是字符設(shè)備。塊設(shè)備被用戶程序通過系統(tǒng)緩沖
6、來訪問。特別是系統(tǒng)內(nèi)存分配和管理進程就沒有必要來充當從外設(shè)讀寫的數(shù)據(jù)傳輸者了。正好與之相反的是,字符設(shè)備直接與用戶程序進行通訊,而且兩者似乎沒有緩沖區(qū)。Linux的傳輸控制機制會根據(jù)用戶程序的需要來正確地操縱內(nèi)存和磁盤等外設(shè)來取得數(shù)據(jù)。在Linux系統(tǒng)中字符設(shè)備驅(qū)動器被保存為/usr/src/linux/drivers/char目錄中。下面我們重點介紹字符設(shè)備驅(qū)動程序的開發(fā)方法。首先了解一下Linux的內(nèi)核編程環(huán)境。我們知道每個Linux用戶進程都在一個獨立的系統(tǒng)空間中運行著,與系統(tǒng)區(qū)和其他用戶進程相隔離。這樣就保護了一個用戶進程的運行環(huán)境,以免被其他用戶進程所破壞。與這種情況正相反的是,設(shè)備
7、驅(qū)動程序運行在內(nèi)核模式,它們具有很大的自由度。這些設(shè)備驅(qū)動程序都是被假設(shè)為正確和可靠的,它們是內(nèi)核的一部分,可以處理系統(tǒng)中斷請求和訪問外圍設(shè)備,同時它們有效地處理中斷請求以便系統(tǒng)調(diào)度程序保持系統(tǒng)需求的平衡。所以設(shè)備驅(qū)動程序可以脫離系統(tǒng)的限制來使用系統(tǒng)區(qū),比如系統(tǒng)的緩沖區(qū)等等。一個設(shè)備驅(qū)動程序同時包括中斷和同步區(qū)域。其中中斷區(qū)域處理實時事件并且被設(shè)備的中斷所驅(qū)動;而同步區(qū)域則組成了設(shè)備的剩余部分,處理進程的同步事件。所以,當一個設(shè)備需要一些軟件服務(wù)時,就發(fā)出一個"中斷",然后中斷處理器得到產(chǎn)生中斷的原因同時進行相應(yīng)的動作。一個Linux進程可能會在事件發(fā)生之前一直等待下去。例
8、如,一個進程可能會在運行中等待一些寫入硬件設(shè)備的信息的到來。其中一種方式是進程可以使用sleep()和wakeup()這兩個系統(tǒng)調(diào)用,進程先使自己處于睡眠狀態(tài),等待事件的到來,一旦事件發(fā)生,進程即可被喚醒。舉個例子來說:interruptible_sleep_on(&dev_wait_queue)函數(shù)使進程睡眠并且將此進程的進程號加到進程睡眠列表dev_wait_queue中,一旦設(shè)備準備好后,設(shè)備發(fā)出一個中斷,從而導(dǎo)致設(shè)備驅(qū)動程序中相應(yīng)的例程被調(diào)用,這個驅(qū)動程序例程處理完一些設(shè)備要求的事宜后會發(fā)出一個喚醒進程的信號,通常使用wake_up_interruptible(&dev
9、_wait_queue)函數(shù),它可以喚醒dev_wait_queue所示列表中的所有進程。特別要注意的是,如果兩個和兩個以上的進程共享一些公共數(shù)據(jù)區(qū)時,我們必須將之視為臨界區(qū),臨界區(qū)保證了進程間互斥地訪問公共數(shù)據(jù)。在Linux系統(tǒng)中我們可以使用cli()和sti()兩個內(nèi)核例程來處理這種互斥,當一個進程在訪問臨界區(qū)時可以使用cli()來關(guān)閉中斷,離開時則使用sti()再將中斷打開,就像下面的寫法:cli()臨界區(qū)sti()除了以上這些,我們還得了解一下虛擬文件系統(tǒng)交換(VFS)的概念。圖6 虛擬文件系統(tǒng)交換圖6中的"文件操作結(jié)構(gòu)"在/usr/include/linux/fs
10、.h文件中定義,此結(jié)構(gòu)包含了驅(qū)動程序中的函數(shù)列表。圖上的初始化例程xxx_init()根據(jù)VFS和設(shè)備的主設(shè)備號來注冊"文件操作結(jié)構(gòu)"。下面是一些設(shè)備驅(qū)動程序的支撐函數(shù)(具體使用方法詳見Linux編程手冊,使用man命令):add_timer() 定時間一過,可以引發(fā)函數(shù)的執(zhí)行;cli() 關(guān)閉中斷,阻止中斷的捕獲;end_request() 當一個請求被完成或被撤銷時被執(zhí)行;free_irq() 釋放一個先前被request_irq()和irqaction()捕獲的的中斷請求;get_fs*() 允許一個設(shè)備驅(qū)動程序訪問用戶區(qū)數(shù)據(jù)(一塊不屬于內(nèi)核的內(nèi)存區(qū));inb(),
11、inb_p() 從一個端口讀取一個字節(jié),其中inb_p() 會一直阻塞直到從端口得到字節(jié)為止;irqaction() 注冊一個中斷;IS_*(inode) 測試inode是否在一個被mount了的文件系統(tǒng)上;kfree*() 放先前被kmalloc()分配的內(nèi)存區(qū);kmalloc() 分配大于4096個字節(jié)的大塊內(nèi)存區(qū);MAJOR() 返回設(shè)備的主設(shè)備號;MINOR() 返回設(shè)備的次設(shè)備號;memcpy_*fs() 在用戶區(qū)和內(nèi)核區(qū)之間復(fù)制大塊的內(nèi)存;outb(), outb_p() 向一個端口寫一個字節(jié),其中outb_p()一直阻塞直到寫字節(jié)成功為止;printk() 內(nèi)核使用的printf
12、()版本;put_fs*() 允許設(shè)備驅(qū)動程序?qū)?shù)據(jù)寫入用戶區(qū);register_*dev() 在內(nèi)核中注冊一個設(shè)備;request_irq() 向內(nèi)核申請一個中斷請求IRQ,如果成功則安裝一個中斷請求處理器;select_wait() 將一個進程加到相應(yīng)select_wait隊列中;*sleep_on() 使進程睡眠以等待事件的到來,并且將wait_queue 入口點加到列表中以便事件到來時將進程喚醒;sti() 和cti()相對應(yīng),恢復(fù)中斷捕獲;sys_get*() 系統(tǒng)調(diào)用,得到進程的有關(guān)信息;wake_up*() 喚醒先前被*sleep_on() 睡眠的進程;Linux的用戶進程不能直
13、接訪問系統(tǒng)物理內(nèi)存。每個用戶進程都有自己的內(nèi)存空間(用戶虛擬地址空間,開始于虛擬0地址)。同樣內(nèi)核也具有自己特定的內(nèi)存空間-系統(tǒng)虛擬地址空間。每當用戶使用系統(tǒng)調(diào)用read()或write()時,設(shè)備驅(qū)動程序就在內(nèi)核地址空間和用戶程序地址空間之間拷貝數(shù)據(jù)。許多Linux例程,比如memcpy_*fs() 和 put_fs*()可以使設(shè)備驅(qū)動程序穿越"用戶系統(tǒng)"邊界來傳輸數(shù)據(jù)。而且數(shù)據(jù)可以是字節(jié)、字或任意長度的數(shù)據(jù)塊。例如,memcpy_fromfs()可以從用戶內(nèi)存空間傳輸任意長度的數(shù)據(jù)塊到設(shè)備,而get_fs_byte()則只從用戶內(nèi)存空間傳輸一個字節(jié);相同的memcpy_
14、tofs()和 put_fs_byte()也是如此,只不過它們是寫數(shù)據(jù)到用戶內(nèi)存空間。然而,在內(nèi)核可訪問內(nèi)存空間和設(shè)備本身之間傳輸數(shù)據(jù)則要視不同的計算機而定。一些計算機需要使用一些特殊CPU輸入輸出指令來完成這項工作,這通常被稱為DMA(直接內(nèi)存訪問)。而另一種方案則是使用內(nèi)存映射I/O來解決,通常使用系統(tǒng)提供的I/O函數(shù),比如inb()和outb()來分別地從I/O地址(即端口)讀取和向I/O地址輸出一單字節(jié),可以使用以下的語句:unsigned char inb(int port)outb(char data, int port)好,下面就可以來看看字符設(shè)備驅(qū)動程序的基本結(jié)構(gòu)。如圖6所示xxx_write()例程輪詢設(shè)備是否已經(jīng)準備好接收數(shù)據(jù),如果準備好了,則將指定長度的字符串從用戶內(nèi)存空間發(fā)送到字符設(shè)備。另外還可以使用中斷來通知設(shè)備是否準備好,這樣就不需要程序為了輪詢而等待,從而提高CPU的利用率。xxx_table是一個結(jié)構(gòu)的數(shù)組,它包含很多成員變量,包括xxx_wait_queue和bytes_xfered(兩者都被用于讀寫操作)。xxx_open()使用request_irq()或irqaction()來調(diào)用xxx_interr
溫馨提示
- 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 勞動教育練習題庫+答案
- 知識產(chǎn)權(quán)交易中的風險管理與控制
- 中國工業(yè)順酐項目投資可行性研究報告
- 2025-2030年中國珍禽行業(yè)深度研究分析報告
- 貴州銅仁數(shù)據(jù)職業(yè)學院《建筑力學二》2023-2024學年第二學期期末試卷
- 湖北黃岡應(yīng)急管理職業(yè)技術(shù)學院《管理專業(yè)外語》2023-2024學年第二學期期末試卷
- 環(huán)保型油墨市場運行態(tài)勢及行業(yè)發(fā)展前景預(yù)測報告
- 律師入伙申請書
- 廣東第二師范學院《進出口商品歸類》2023-2024學年第二學期期末試卷
- 昆明城市學院《機電一體化技術(shù)及系統(tǒng)設(shè)計》2023-2024學年第二學期期末試卷
- 2024年初級養(yǎng)老護理員職業(yè)鑒定考試題庫(含答案)
- 人教八年級上冊英語第一單元《Section A (1a-2d)》教學課件
- 2023年版《安寧療護實踐指南(試行)》解讀課件
- 2024年銀行考試-興業(yè)銀行筆試考試歷年高頻考點試題摘選含答案
- 油氣勘探開發(fā)的勘探風險管理
- 10kV環(huán)網(wǎng)柜改造工程施工方案設(shè)計
- 電工班三級安全教育內(nèi)容范本
- 新生兒疾病篩查可疑陽性、陽性兒復(fù)查隨訪登記表
- 開學前幼兒園安全培訓
- 2024年春學期人教版pep版小學英語五年級下冊教學進度表
- 2023年湛江市麻章區(qū)教育局招聘事業(yè)編制教師考試真題
評論
0/150
提交評論