如何編寫Linux裝置驅動程式

2021-03-04 05:21:59 字數 2899 閱讀 3138

序言linux是unix作業系統的一種變種,在linux下編寫驅動程式的原理和思想完全類似於其他的unix系統,但它dos或window環境下的驅動程式有很大的區別。在linux環境下設計驅動程式,思想簡潔,操作方便,功能也很強大,但是支援函式少,只能依賴kernel中的函式,有些常用的操作要自己來編寫,而且除錯也不方便。本人這幾周來為實驗室自行研製的一塊多**卡編制了驅動程式,獲得了一些經驗,願與linux fans共享,有不當之處,請予指正。

以下的一些文字主要**於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.

//hehe

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

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

二、例項剖析

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

不過我的kernel是2.0.34,在低版本的kernel上可能會出現問題,我還沒測試過.

//xixi

#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 = ;

Linux作業系統網路驅動程式編寫詳解

一.降阻模組使用方法 接地系統 壞在很大程度上決定於施工質量的優劣,因為掌握正確的施工方法和工藝質量要求是很必要的。接地工程施工通常應遵循以下基本原則 1 在有效長度範圍內,盡可能選擇在土壤電阻率小的地方埋設接地模組。2 接地模組的埋設地點應遠離熱源和盡量避開有強腐蝕性物質的地方。3 接地模組的埋設...

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

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

Linux裝置驅動程式的概念 作用以及模組

我們首先對linux系統整個框架要有個了解。linux簡化了分段機制,使得虛擬位址與線性位址總是一致,因此,linux的虛擬位址空間也為0 4g。linux核心將這4g位元組的空間分為兩部分,分別是使用者空間 0 3g 和核心空間 3g 4g 其中,使用者空間存放的是應用程式,而核心空間存放的是核心...