Linux課件如何編寫Linux裝置驅動程式

2021-07-11 12:19:13 字數 3633 閱讀 5429

linux是unix作業系統的一種變種,在linux下編寫驅動程式的原理和思想完全類似於其他的unix系統,但它dos或window環境下的驅動程式有很大的區別。在linux環境下設計驅動程式,思想簡潔,操作方便,功能也很強大,但是支援函式少,只能依賴kernel中的函式,有些常用的操作要自己來編寫,而且除錯也不方便。

以下的一些文字主要**於khg,johnsonm的write linux device driver,brennan's guide to inline assembly,the linux a-z,還有清華bbs上的有關device driver的一些資料。

一、linux device driver 的概念

系統呼叫是作業系統核心和應用程式之間的介面,裝置驅動程式是作業系統核心和機器硬體之間的介面。裝置驅動程式為應用程式遮蔽了硬體的細節,這樣在應用程式看來,硬體裝置只是乙個裝置檔案,應用程式可以象操作普通檔案一樣對硬體裝置進行操作。裝置驅動程式是核心的一部分,它完成以下的功能:

1。對裝置初始化和釋放。

2。把資料從核心傳送到硬體和從硬體讀取資料。

3。讀取應用程式傳送給裝置檔案的資料和回送應用程式請求的資料。

4。檢測和處理裝置出現的錯誤。

在linux作業系統下有三類主要的裝置檔案型別,一是字元裝置,二是塊裝置,三是網路裝置。字元裝置和塊裝置的主要區別是:在對字元裝置發出讀/寫請求時,實際的硬體i/o一般就緊接著發生了,塊裝置則不然,它利用一塊系統記憶體作緩衝區,當使用者程序對裝置請求能滿足使用者的要求,就返回請求的資料,如果不能,就呼叫請求函式來進行實際的i/o操作。

塊裝置是主要針對磁碟等慢速裝置設計的,以免耗費過多的cpu時間來等待。

已經提到,使用者程序是通過裝置檔案來與實際的硬體打交道。每個裝置檔案都都有其檔案屬性(c/b),表示是字元裝置還是塊裝置?另外每個檔案都有兩個裝置號,第乙個是主裝置號,標識驅動程式,第二個是從裝置號,標識使用同乙個裝置驅動程式的不同的硬體裝置,比如有兩個軟盤,就可以用從裝置號來區分他們。

裝置檔案的的主裝置號必須與裝置驅動程式在登記時申請的主裝置號一致,否則使用者程序將無法訪問到驅動程式。

最後必須提到的是,在使用者程序呼叫驅動程式時,系統進入核心態,這時不再是搶先式排程。也就是說,系統必須在你的驅動程式的子函式返回後才能進行其他的工作。如果你的驅動程式陷入死迴圈,不幸的是你只有重新啟動機器了,然後就是漫長的fsck。

讀/寫時,它首先察看緩衝區的內容,如果緩衝區的資料

如何編寫linux作業系統下的裝置驅動程式

二、例項剖析

我們來寫乙個最簡單的字元裝置驅動程式。雖然它什麼也不做,但是通過它可以了解linux的裝置驅動程式的工作原理。把下面的c**輸入機器,你就會獲得乙個真正的裝置驅動程式。

#define __no_version__

#include

#include

char kernel_version = uts_release;

這一段定義了一些版本資訊,雖然用處不是很大,但也必不可少。johnsonm說所有的驅動程式的開頭都要包含,一般來講最好使用。

由於使用者程序是通過裝置檔案同硬體打交道,對裝置檔案的操作方式不外乎就是一些系統呼叫,如 open,read,write,close…, 注意,不是fopen, fread,但是如何把系統呼叫和驅動程式關聯起來呢?這需要了解乙個非常關鍵的資料結構:

struct file_operations

這個結構的每乙個成員的名字都對應著乙個系統呼叫。使用者程序利用系統呼叫在對裝置檔案進行諸如read/write操作時,系統呼叫通過裝置檔案的主裝置號找到相應的裝置驅動程式,然後讀取這個資料結構相應的函式指標,接著把控制權交給該函式。這是linux的裝置驅動程式工作的基本原理。

既然是這樣,則編寫裝置驅動程式的主要工作就是編寫子函式,並填充file_operations的各個域。

下面就開始寫子程式。

#include

#include

#include

#include

#include

unsigned int test_major = 0;

static int read_test(struct inode *node,struct file *file,char *buf,int count)

return count;

} 這個函式是為read呼叫準備的。當呼叫read時,read_test()被呼叫,它把使用者的緩衝區全部寫1。buf 是read呼叫的乙個引數。

它是使用者程序空間的乙個位址。但是在read_test被呼叫時,系統進入核心態。所以不能使用buf這個位址,必須用__put_user(),這是kernel提供的乙個函式,用於向使用者傳送資料。

另外還有很多類似功能的函式。請參考,在向使用者空間拷貝資料之前,必須驗證buf是否可用。這就用到函式verify_area。

static int write_tibet(struct inode *inode,struct file *file,const char *buf,int count)

static int open_tibet(struct inode *inode,struct file *file )

static void release_tibet(struct inode *inode,struct file *file )

這幾個函式都是空操作。實際呼叫發生時什麼也不做,他們僅僅為下面的結構提供函式指標。

struct file_operations test_fops = ;

裝置驅動程式的主體可以說是寫好了。現在要把驅動程式嵌入核心。驅動程式可以按照兩種方式編譯。

一種是編譯進kernel,另一種是編譯成模組(modules),如果編譯進核心的話,會增加核心的大小,還要改動核心的原始檔,而且不能動態的解除安裝,不利於除錯,所以推薦使用模組方式。

int init_module(void)

if (test_major == 0) test_major = result; /* dynamic */

return 0;

}   在用insmod命令將編譯好的模組調入記憶體時,init_module 函式被呼叫。在這裡,init_module只做了一件事,就是向系統的字元裝置表登記了乙個字元裝置。register_chrdev需要三個引數,引數一是希望獲得的裝置號,如果是零的話,系統將選擇乙個沒有被占用的裝置號返回。

引數二是裝置檔名,引數三用來登記驅動程式實際執行操作的函式的指標。

如果登記成功,返回裝置的主裝置號,不成功,返回乙個負值。

void cleanup_module(void)

在用rmmod解除安裝模組時,cleanup_module函式被呼叫,它釋放字元裝置test在系統字元裝置表中占有的表項。

乙個極其簡單的字元裝置可以說寫好了,檔名就叫test.c吧。

下面編譯 :

$ gcc -o2 -dmodule -d__kernel__ -c test.c

得到檔案test.o就是乙個裝置驅動程式。

如果裝置驅動程式有多個檔案,把每個檔案按上面的命令列編譯,然後

ld -r file1.o file2.o -o modulename。

驅動程式已經編譯好了,現在把它安裝到系統中去。

$ insmod –f test.o

如果安裝成功,在/proc/devices檔案中就可以看到裝置test,並可以看到它的主裝置號。要解除安裝的話,執行 :

$ rmmod test

如何編寫Linux裝置驅動程式

序言linux是unix作業系統的一種變種,在linux下編寫驅動程式的原理和思想完全類似於其他的unix系統,但它dos或window環境下的驅動程式有很大的區別。在linux環境下設計驅動程式,思想簡潔,操作方便,功能也很強大,但是支援函式少,只能依賴kernel中的函式,有些常用的操作要自己來...

Linux 期末考試試題8套 含答案 linux期末

linux 期末考試試題 一 一 選擇題 每小題2分,共50分 1.在建立linux分割槽時,一定要建立 d 兩個分割槽 a.fat ntfs b.fat swap c.ntfs swap 根分割槽 2.在red hat linux 9中,系統預設的 a 使用者對整個系統擁有完全的控制權。a.roo...

如何編寫教案

教師要上好課,必須做好課堂教學準備,即備好課。教學好比演戲,而備課過程如同編寫劇本 排劇 舞台設計等準備演出的過程。教師擔任著編劇 導演 主演 劇務等全部工作。可見,備課既是一項艱苦的腦力勞動,又是一門創造性的藝術。教師通過大量的備課活動,所要達到的直接目的,就是制定出比較完善的課時授課計畫,即教案...