Linux系統(tǒng)的硬件驅(qū)動(dòng)程序編寫(xiě)原理_第1頁(yè)
Linux系統(tǒng)的硬件驅(qū)動(dòng)程序編寫(xiě)原理_第2頁(yè)
Linux系統(tǒng)的硬件驅(qū)動(dòng)程序編寫(xiě)原理_第3頁(yè)
Linux系統(tǒng)的硬件驅(qū)動(dòng)程序編寫(xiě)原理_第4頁(yè)
Linux系統(tǒng)的硬件驅(qū)動(dòng)程序編寫(xiě)原理_第5頁(yè)
已閱讀5頁(yè),還剩5頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、Linux系統(tǒng)的硬件驅(qū)動(dòng)程序編寫(xiě)原理*本文詳細(xì)地介紹如何Linux系統(tǒng)的硬件驅(qū)動(dòng)程序的編寫(xiě)原理,指出哪些內(nèi)核例程將會(huì)被調(diào)用、如何初始化驅(qū)動(dòng)程序及如何分配內(nèi)存等等。大家一定對(duì)Linux操作系統(tǒng)有所了解了,在此本人也不再贅述了。好吧,下面簡(jiǎn)單地介紹一下設(shè)備驅(qū)動(dòng)程序。顧名思義,驅(qū)動(dòng)程序是用來(lái)控制計(jì)算機(jī)外圍設(shè)備的,Linux系統(tǒng)將所有的外圍設(shè)備都高度地抽象成一些字節(jié)的序列,并且以文件的形式來(lái)表示這些設(shè)備。我們可以來(lái)看一下Linux的I/O子系統(tǒng)(圖1)。圖1 Linux的I/O子系統(tǒng)從圖上我們可以看出,內(nèi)核緊緊地包圍在硬件周?chē)瑑?nèi)核是一些軟件包的組合,它們可以直接訪問(wèn)系統(tǒng)的硬件,包括處理器、內(nèi)存和I/

2、O設(shè)備。而用戶(hù)進(jìn)程則通過(guò)內(nèi)核提供的用戶(hù)服務(wù)來(lái)和內(nèi)核通訊,從而間接地控制系統(tǒng)硬件。我們可以通過(guò)圖2來(lái)了解這些動(dòng)作的具體情況。 圖2 用戶(hù)級(jí)、內(nèi)核級(jí)和硬件級(jí)三者之間的通訊圖上顯示了用戶(hù)級(jí)的程序使用內(nèi)核提供的標(biāo)準(zhǔn)系統(tǒng)調(diào)用來(lái)與內(nèi)核通訊,這些系統(tǒng)調(diào)用有:open(), read(), write(), ioctl(), close() 等等。Linux的內(nèi)核是一個(gè)有機(jī)的整體。每一個(gè)用戶(hù)進(jìn)程運(yùn)行時(shí)都好像有一份內(nèi)核的拷貝,每當(dāng)用戶(hù)進(jìn)程使用系統(tǒng)調(diào)用時(shí),都自動(dòng)地將運(yùn)行模式從用戶(hù)級(jí)轉(zhuǎn)為內(nèi)核級(jí),此時(shí)進(jìn)程在內(nèi)核的地址空間中運(yùn)行。圖3 Linux的I/O子系統(tǒng)Linux內(nèi)核使用"設(shè)備無(wú)關(guān)"的I/O子

3、系統(tǒng)來(lái)為所有的設(shè)備服務(wù)。每個(gè)設(shè)備都提供標(biāo)準(zhǔn)接口給內(nèi)核,從而盡可能地隱藏了自己的特性。圖3展示了用戶(hù)程序使用一些基本的系統(tǒng)調(diào)用從設(shè)備讀取數(shù)據(jù)并且將它們存入緩沖的例子。我們可以看到,每當(dāng)一個(gè)系統(tǒng)調(diào)用被使用時(shí),內(nèi)核就轉(zhuǎn)到相應(yīng)的設(shè)備驅(qū)動(dòng)例程來(lái)操縱硬件。每個(gè)設(shè)備在Linux系統(tǒng)上看起來(lái)都像一個(gè)文件,它們存放在/dev目錄中并被稱(chēng)為"特殊文件"或是"設(shè)備節(jié)點(diǎn)"。大家可以使用ls -l /dev/lp* 來(lái)得到以下的輸出: crw-rw-rw 1 root root 6, 0 April 23 1994 /dev/lp0 這行輸出表示lp0是一個(gè)字符設(shè)備(屬性字段的第

4、一個(gè)字符是'c'),主設(shè)備號(hào)是6,次設(shè)備號(hào)是0。主設(shè)備號(hào)用來(lái)向內(nèi)核表明這一設(shè)備節(jié)點(diǎn)所代表的驅(qū)動(dòng)程序的類(lèi)型(比如:主設(shè)備號(hào)是3的塊設(shè)備是IDE磁盤(pán)驅(qū)動(dòng)程序,而主設(shè)備號(hào)為8的塊設(shè)備是SCSI磁盤(pán)驅(qū)動(dòng)程序);每個(gè)驅(qū)動(dòng)程序負(fù)責(zé)管理它所驅(qū)動(dòng)的幾個(gè)硬件實(shí)例,這些硬件實(shí)例則由次設(shè)備號(hào)來(lái)表示(例如:次設(shè)備號(hào)為0的SCSI磁盤(pán)代表整個(gè)也可以說(shuō)是"第一個(gè)"SCSI磁盤(pán),而次設(shè)備號(hào)為1到15的磁盤(pán)代表此SCSI磁盤(pán)上的15個(gè)分區(qū))。到此大家應(yīng)該對(duì)Linux的設(shè)備有所了解了吧,下面就可以開(kāi)始我們的正題"設(shè)備驅(qū)動(dòng)程序"。設(shè)備驅(qū)動(dòng)程序是一組由內(nèi)核中的相關(guān)子例程和數(shù)據(jù)

5、組成的I/O設(shè)備軟件接口。每當(dāng)內(nèi)核意識(shí)到要對(duì)某個(gè)設(shè)備進(jìn)行特殊的操作時(shí),它就調(diào)用相應(yīng)的驅(qū)動(dòng)例程。這就使得控制從用戶(hù)進(jìn)程轉(zhuǎn)移到了驅(qū)動(dòng)例程,當(dāng)驅(qū)動(dòng)例程完成后,控制又被返回至用戶(hù)進(jìn)程。圖5就顯示了以上的過(guò)程。圖5 設(shè)備驅(qū)動(dòng)程序的作用每個(gè)設(shè)備驅(qū)動(dòng)程序都具有以下幾個(gè)特性:l 具有一整套的和硬件設(shè)備通訊的例程,并且提供給操作系統(tǒng)一套標(biāo)準(zhǔn)的軟件接口;l 具有一個(gè)可以被操作系統(tǒng)動(dòng)態(tài)地調(diào)用和移除的自包含組件;l 可以控制和管理用戶(hù)程序和物理設(shè)備之間的數(shù)據(jù)流。接下來(lái)我們來(lái)了解一下字符設(shè)備和塊設(shè)備,它們是Linux系統(tǒng)中兩種主要的外圍設(shè)備。我們常見(jiàn)的磁盤(pán)是塊設(shè)備,而終端和打印機(jī)是字符設(shè)備。塊設(shè)備被用戶(hù)程序通過(guò)系統(tǒng)緩沖

6、來(lái)訪問(wèn)。特別是系統(tǒng)內(nèi)存分配和管理進(jìn)程就沒(méi)有必要來(lái)充當(dāng)從外設(shè)讀寫(xiě)的數(shù)據(jù)傳輸者了。正好與之相反的是,字符設(shè)備直接與用戶(hù)程序進(jìn)行通訊,而且兩者似乎沒(méi)有緩沖區(qū)。Linux的傳輸控制機(jī)制會(huì)根據(jù)用戶(hù)程序的需要來(lái)正確地操縱內(nèi)存和磁盤(pán)等外設(shè)來(lái)取得數(shù)據(jù)。在Linux系統(tǒng)中字符設(shè)備驅(qū)動(dòng)器被保存為/usr/src/linux/drivers/char目錄中。下面我們重點(diǎn)介紹字符設(shè)備驅(qū)動(dòng)程序的開(kāi)發(fā)方法。首先了解一下Linux的內(nèi)核編程環(huán)境。我們知道每個(gè)Linux用戶(hù)進(jìn)程都在一個(gè)獨(dú)立的系統(tǒng)空間中運(yùn)行著,與系統(tǒng)區(qū)和其他用戶(hù)進(jìn)程相隔離。這樣就保護(hù)了一個(gè)用戶(hù)進(jìn)程的運(yùn)行環(huán)境,以免被其他用戶(hù)進(jìn)程所破壞。與這種情況正相反的是,設(shè)備

7、驅(qū)動(dòng)程序運(yùn)行在內(nèi)核模式,它們具有很大的自由度。這些設(shè)備驅(qū)動(dòng)程序都是被假設(shè)為正確和可靠的,它們是內(nèi)核的一部分,可以處理系統(tǒng)中斷請(qǐng)求和訪問(wèn)外圍設(shè)備,同時(shí)它們有效地處理中斷請(qǐng)求以便系統(tǒng)調(diào)度程序保持系統(tǒng)需求的平衡。所以設(shè)備驅(qū)動(dòng)程序可以脫離系統(tǒng)的限制來(lái)使用系統(tǒng)區(qū),比如系統(tǒng)的緩沖區(qū)等等。一個(gè)設(shè)備驅(qū)動(dòng)程序同時(shí)包括中斷和同步區(qū)域。其中中斷區(qū)域處理實(shí)時(shí)事件并且被設(shè)備的中斷所驅(qū)動(dòng);而同步區(qū)域則組成了設(shè)備的剩余部分,處理進(jìn)程的同步事件。所以,當(dāng)一個(gè)設(shè)備需要一些軟件服務(wù)時(shí),就發(fā)出一個(gè)"中斷",然后中斷處理器得到產(chǎn)生中斷的原因同時(shí)進(jìn)行相應(yīng)的動(dòng)作。一個(gè)Linux進(jìn)程可能會(huì)在事件發(fā)生之前一直等待下去。例

8、如,一個(gè)進(jìn)程可能會(huì)在運(yùn)行中等待一些寫(xiě)入硬件設(shè)備的信息的到來(lái)。其中一種方式是進(jìn)程可以使用sleep()和wakeup()這兩個(gè)系統(tǒng)調(diào)用,進(jìn)程先使自己處于睡眠狀態(tài),等待事件的到來(lái),一旦事件發(fā)生,進(jìn)程即可被喚醒。舉個(gè)例子來(lái)說(shuō):interruptible_sleep_on(&dev_wait_queue)函數(shù)使進(jìn)程睡眠并且將此進(jìn)程的進(jìn)程號(hào)加到進(jìn)程睡眠列表dev_wait_queue中,一旦設(shè)備準(zhǔn)備好后,設(shè)備發(fā)出一個(gè)中斷,從而導(dǎo)致設(shè)備驅(qū)動(dòng)程序中相應(yīng)的例程被調(diào)用,這個(gè)驅(qū)動(dòng)程序例程處理完一些設(shè)備要求的事宜后會(huì)發(fā)出一個(gè)喚醒進(jìn)程的信號(hào),通常使用wake_up_interruptible(&dev

9、_wait_queue)函數(shù),它可以喚醒dev_wait_queue所示列表中的所有進(jìn)程。特別要注意的是,如果兩個(gè)和兩個(gè)以上的進(jìn)程共享一些公共數(shù)據(jù)區(qū)時(shí),我們必須將之視為臨界區(qū),臨界區(qū)保證了進(jìn)程間互斥地訪問(wèn)公共數(shù)據(jù)。在Linux系統(tǒng)中我們可以使用cli()和sti()兩個(gè)內(nèi)核例程來(lái)處理這種互斥,當(dāng)一個(gè)進(jìn)程在訪問(wèn)臨界區(qū)時(shí)可以使用cli()來(lái)關(guān)閉中斷,離開(kāi)時(shí)則使用sti()再將中斷打開(kāi),就像下面的寫(xiě)法:cli()臨界區(qū)sti()除了以上這些,我們還得了解一下虛擬文件系統(tǒng)交換(VFS)的概念。圖6 虛擬文件系統(tǒng)交換圖6中的"文件操作結(jié)構(gòu)"在/usr/include/linux/fs

10、.h文件中定義,此結(jié)構(gòu)包含了驅(qū)動(dòng)程序中的函數(shù)列表。圖上的初始化例程xxx_init()根據(jù)VFS和設(shè)備的主設(shè)備號(hào)來(lái)注冊(cè)"文件操作結(jié)構(gòu)"。下面是一些設(shè)備驅(qū)動(dòng)程序的支撐函數(shù)(具體使用方法詳見(jiàn)Linux編程手冊(cè),使用man命令):add_timer() 定時(shí)間一過(guò),可以引發(fā)函數(shù)的執(zhí)行;cli() 關(guān)閉中斷,阻止中斷的捕獲;end_request() 當(dāng)一個(gè)請(qǐng)求被完成或被撤銷(xiāo)時(shí)被執(zhí)行;free_irq() 釋放一個(gè)先前被request_irq()和irqaction()捕獲的的中斷請(qǐng)求;get_fs*() 允許一個(gè)設(shè)備驅(qū)動(dòng)程序訪問(wèn)用戶(hù)區(qū)數(shù)據(jù)(一塊不屬于內(nèi)核的內(nèi)存區(qū));inb(),

11、inb_p() 從一個(gè)端口讀取一個(gè)字節(jié),其中inb_p() 會(huì)一直阻塞直到從端口得到字節(jié)為止;irqaction() 注冊(cè)一個(gè)中斷;IS_*(inode) 測(cè)試inode是否在一個(gè)被mount了的文件系統(tǒng)上;kfree*() 放先前被kmalloc()分配的內(nèi)存區(qū);kmalloc() 分配大于4096個(gè)字節(jié)的大塊內(nèi)存區(qū);MAJOR() 返回設(shè)備的主設(shè)備號(hào);MINOR() 返回設(shè)備的次設(shè)備號(hào);memcpy_*fs() 在用戶(hù)區(qū)和內(nèi)核區(qū)之間復(fù)制大塊的內(nèi)存;outb(), outb_p() 向一個(gè)端口寫(xiě)一個(gè)字節(jié),其中outb_p()一直阻塞直到寫(xiě)字節(jié)成功為止;printk() 內(nèi)核使用的printf

12、()版本;put_fs*() 允許設(shè)備驅(qū)動(dòng)程序?qū)?shù)據(jù)寫(xiě)入用戶(hù)區(qū);register_*dev() 在內(nèi)核中注冊(cè)一個(gè)設(shè)備;request_irq() 向內(nèi)核申請(qǐng)一個(gè)中斷請(qǐng)求IRQ,如果成功則安裝一個(gè)中斷請(qǐng)求處理器;select_wait() 將一個(gè)進(jìn)程加到相應(yīng)select_wait隊(duì)列中;*sleep_on() 使進(jìn)程睡眠以等待事件的到來(lái),并且將wait_queue 入口點(diǎn)加到列表中以便事件到來(lái)時(shí)將進(jìn)程喚醒;sti() 和cti()相對(duì)應(yīng),恢復(fù)中斷捕獲;sys_get*() 系統(tǒng)調(diào)用,得到進(jìn)程的有關(guān)信息;wake_up*() 喚醒先前被*sleep_on() 睡眠的進(jìn)程;Linux的用戶(hù)進(jìn)程不能直

13、接訪問(wèn)系統(tǒng)物理內(nèi)存。每個(gè)用戶(hù)進(jìn)程都有自己的內(nèi)存空間(用戶(hù)虛擬地址空間,開(kāi)始于虛擬0地址)。同樣內(nèi)核也具有自己特定的內(nèi)存空間-系統(tǒng)虛擬地址空間。每當(dāng)用戶(hù)使用系統(tǒng)調(diào)用read()或write()時(shí),設(shè)備驅(qū)動(dòng)程序就在內(nèi)核地址空間和用戶(hù)程序地址空間之間拷貝數(shù)據(jù)。許多Linux例程,比如memcpy_*fs() 和 put_fs*()可以使設(shè)備驅(qū)動(dòng)程序穿越"用戶(hù)系統(tǒng)"邊界來(lái)傳輸數(shù)據(jù)。而且數(shù)據(jù)可以是字節(jié)、字或任意長(zhǎng)度的數(shù)據(jù)塊。例如,memcpy_fromfs()可以從用戶(hù)內(nèi)存空間傳輸任意長(zhǎng)度的數(shù)據(jù)塊到設(shè)備,而get_fs_byte()則只從用戶(hù)內(nèi)存空間傳輸一個(gè)字節(jié);相同的memcpy_

14、tofs()和 put_fs_byte()也是如此,只不過(guò)它們是寫(xiě)數(shù)據(jù)到用戶(hù)內(nèi)存空間。然而,在內(nèi)核可訪問(wèn)內(nèi)存空間和設(shè)備本身之間傳輸數(shù)據(jù)則要視不同的計(jì)算機(jī)而定。一些計(jì)算機(jī)需要使用一些特殊CPU輸入輸出指令來(lái)完成這項(xiàng)工作,這通常被稱(chēng)為DMA(直接內(nèi)存訪問(wèn))。而另一種方案則是使用內(nèi)存映射I/O來(lái)解決,通常使用系統(tǒng)提供的I/O函數(shù),比如inb()和outb()來(lái)分別地從I/O地址(即端口)讀取和向I/O地址輸出一單字節(jié),可以使用以下的語(yǔ)句:unsigned char inb(int port)outb(char data, int port)好,下面就可以來(lái)看看字符設(shè)備驅(qū)動(dòng)程序的基本結(jié)構(gòu)。如圖6所示xxx_write()例程輪詢(xún)?cè)O(shè)備是否已經(jīng)準(zhǔn)備好接收數(shù)據(jù),如果準(zhǔn)備好了,則將指定長(zhǎng)度的字符串從用戶(hù)內(nèi)存空間發(fā)送到字符設(shè)備。另外還可以使用中斷來(lái)通知設(shè)備是否準(zhǔn)備好,這樣就不需要程序?yàn)榱溯喸?xún)而等待,從而提高CPU的利用率。xxx_table是一個(gè)結(jié)構(gòu)的數(shù)組,它包含很多成員變量,包括xxx_wait_queue和bytes_xfered(兩者都被用于讀寫(xiě)操作)。xxx_open()使用request_irq()或irqaction()來(lái)調(diào)用xxx_interr

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 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ì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論