昨天我們對linux核心的子系統進行簡單的認識,今天我們正式進入驅動的開發,我們今後的學習為了避免大家沒有硬體的缺陷,我們都會以虛拟的裝置為例進行學習,是以大家不必害怕沒有硬體的問題。
今天我們會分析到以下内容:
1. 字元裝置驅動基礎
2. 簡單字元裝置驅動實作
3. 驅動測試
1. 字元裝置描述結構
在linux2.6核心中,使用cdev結構體描述一個字元裝置,其定義如下:
上面結構中需要我們進行初始化的有ops和dev,下面我們會對這兩個成員進行分析。
注:kobject結構是驅動中很重要的一個結構,由于其複雜性,我們現在不進行介紹,後面會詳細介紹。
2. 裝置号
1. 何為裝置号:cdev結構體中dev成員定義了裝置号,而dev_t則為U32類型的也就是32位,其中12位為主裝置号,20位為次裝置号。我們執行ls –l /dev/可看到下圖,其中左邊紅框為主裝置号,右邊為次裝置号
2. 何為主裝置号:用來對應該裝置為何種類型裝置。(比如序列槽我們用一個數字識别,而序列槽有好幾個)
3. 何為次裝置号:用來對應同一類型裝置下的具體裝置。(用次裝置号來具體區分是哪個序列槽)
4. 裝置号相關操作:
1. 通過主裝置号和次裝置号擷取dev:dev = MKDEV(主,次);
2. 通過dev擷取主裝置号:主 = MAJOR(dev);
3. 通過dev擷取次裝置号:dev = MINOR(dev);
5. 裝置号配置設定:裝置号的配置設定有兩種方式,一種是靜态的,另一種是動态的,下面一一分析
1. 靜态配置設定:也就是程式員自己指定裝置号,通過register_chrdev_region();函數向核心申請,可能會導緻和核心已有的沖突,進而失敗。
2. 動态配置設定:通過 alloc_chrdev_region(); 函數向核心申請裝置号。
3. 釋放裝置号:通過 unregister_chrdev_region(); 釋放申請到的裝置号。
3. file_operations操作函數集
file_operations結構體中的成員函數在我們驅動開發過程中極為重要,其中的内容相當龐大,下面我們看看其定義:
View Code
上面結構體中的函數指針所指向的函數,在我們在進行open、write、read等系統調用的時候最終會被調用到,是以我們的驅動中想為應用層實作那種調用就要在此實作。
4. 字元裝置驅動初始化
我們通過上面的分析對裝置号和操作函數集有了一定的了解下面我們來看字元裝置驅動初始化,其主要步驟如下。
1. 配置設定cdev結構:有靜态(直接定義)動态(cdev_alloc();)兩種方式
2. 初始化cdev結構:使用 cdev_init(struct cdev *cdev, const struct file_operations *fops) 初始化
3. 驅動注冊:使用 int cdev_add(struct cdev *p, dev_t dev, unsigned count)//count為該種類型的裝置個數注冊
4. 硬體初始化:閱讀晶片手冊進行硬體裝置的初始化
5. 完成操作函數集:實作要用的操作(裝置方法)
6. 驅動登出:使用 void cdev_del(struct cdev *p) 登出
5. 字元裝置驅動模型及調用關系
下面我通過一張圖将字元裝置的驅動結構、以及字元裝置驅動與使用者空間的調用關系進行展示:
6. 遺漏知識
我們核心空間和使用者空間的資料互動要用到下面兩個函數:
l 簡單字元裝置驅動實作
1. 字元裝置驅動編寫
因為驅動本身就是一個核心子產品,下面的字元裝置驅動隻實作了部分方法,在後面的部落格中我們會基于此驅動慢慢修改,希望大家掌握。
l 驅動測試
1. 加載核心子產品
我們使用 insmod memdev.ko 指令加載核心子產品
2. 擷取裝置号
我們的裝置号是動态申請到的,是以我們要通過下面的指令檢視裝置号
cat /proc/devices
找到我們的裝置memdev的裝置号
3. 建立裝置檔案
使用如下指令建立裝置檔案
mknod /dev/檔案名 c 主裝置号次裝置号
上面指令中檔案名為我們在應用程式中打開的檔案名
c代表字元裝置
主裝置号為上一步找到的,我的位249
次裝置号非負即可,但不能超過自己所建立的裝置數。
比如我的就是 mknod /dev/memdev0 c 249 0
4. 編譯應用程式并測試
使用gcc對應用程式進行編譯,然後先使用write對裝置進行寫入,在使用read對裝置讀取,完成測試。