1. 程式人生 > >字元裝置驅動(globalmem-全域性記憶體)分析之一

字元裝置驅動(globalmem-全域性記憶體)分析之一

globalmem相信學驅動的入門的時候都見過吧

熟悉了模組程式設計的基本框架後,我們就可以試著分析一個簡單的字元裝置驅動。

下面以《裝置驅動開發詳解》一書中的程式碼6.17為例來分析這個字元裝置驅動的程式碼。

我們現在對於對前文中hello,kernel核心模組進行稍微的改動。我們都知道核心模組的入口函式是module_init(function name)內註冊的函式。也就是告訴核心“從這個函式入口”。那麼我們分析字元裝置驅動模組,首先應該去看globalmem_init函式。

在globalmem_init函式中,首先通過巨集MKDEV獲得32位的裝置驅動號。通常linux中的裝置號由主裝置號和次裝置號組成,主裝置號對應每一類裝置,而次裝置號對應該類裝置的具體一個裝置。dev_t型別前12位是主裝置號(但事實上主裝置號的前四位被遮蔽了,如果去看原始碼就可得知),後20位為次裝置號。由於可以事先指定主裝置號globalmem_major,因此我們需要用巨集MKDEV來獲得dev_t型別的裝置號:

這個巨集通過移位和或運算,巧妙的得到dev_t型別的裝置號。這個巨集可以在include/linux/kdev_t.h中查詢到。網上有的資料中會給出MINORBITS為8,這個應該是適合16位的裝置號的情況。

接著通過全域性變數globamem_major來判斷是否事先分配了起始的裝置號。如果是,則繼續分配連續的一段裝置號,否則動態分配裝置號,並且通過MAJOR巨集獲得分配以後的主裝置號。這裡需要強調的是,下面的兩種裝置號分配函式,都是一次性分配一組連續的裝置號(當然也可以只分配一個裝置號,調整引數即可)。

首先我們分析已知起始裝置號的情況。通過呼叫register_chrdev_region函式,便可以申請到一組連續範圍的裝置號。在linux/fs/char_dev.c中可以看到此函式的原型。

其中from是首裝置號,而count是這組連續裝置號的數目。name為裝置名。而《裝置》一書中的count為1,也就是說,這組裝置號的數量為1。

其次,當起始裝置號並未指定時就要動態的申請了,使用下面的函式:

與上面靜態分配函式不同的是,此時dev是一個指標型別,因為要返回將要分配的裝置號。關於以上兩個函式的核心原始碼分析,具體參見這裡

以上都成功執行後,我們給globalmem_devp指標分配記憶體空間。其中globalmem_devp是一個指向globalmem裝置結構體的指標。我們通過mmset對此塊記憶體空間進行初始化之後。接著globalmem_setup_cdev函式對cdev初始化並將此字元設備註冊到

核心。

上面的程式已經很“整齊”的說明了init函式的主要作用。具體如下:

1.申請裝置號

2.為裝置相關的資料結構分配記憶體

3.初始化並註冊cdev(globalmem_setup_cdev函式實現)

有了字元裝置驅動的載入函式,那麼肯定有解除安裝函式:

總體來看,globalmem_init函式完成的是字元裝置的一些初始化工作,以及向系統內註冊。而globalmem_exit就是進行字元裝置的釋放工作:從核心中刪除這個字元裝置,釋放裝置結構體所佔的記憶體,以及釋放申請的裝置號。從結構上看,它並沒有偏離核心模組程式設計的結構範圍,仍然是我們熟悉的hello,kernel。

我們在此先暫時將globalmem_setup_cdev函式內部的實現用return 0;來代替。那麼我們現在用插入核心模組的命令將我們這個字元裝置驅動(儘管許多功能還未實現)插入到核心中。成功後我們可以通過cat /proc/devices 命令來檢視剛剛字元裝置名稱以及主裝置號。/proc是一個虛擬的檔案系統,這裡的虛擬是指這個檔案系統並不佔用磁碟空間而只存在於記憶體中。而該目錄下的devices檔案中儲存著系統字元和塊裝置的驅動名稱以及裝置編號。

接下來,我們可以通過:mknod /dev/globalmem c 250 0命令建立一個裝置節點。有了這個裝置節點後,就可以對它進行類似普通檔案那樣的操作了(當然現在還不能,因為並未實現具體的操作函式)。

這樣一個字元驅動的大致上有了雛形。