占華林 徐濤濤 陳亮亮 于子正 李明鑫
(江西科技師范大學,江西南昌 330013)
任何一個計算機系統的運轉都是系統中軟硬件共同努力的結果,沒有硬件的軟件是空中樓閣,而沒有軟件的硬件則只是一堆廢鐵。計算機系統發現外部設備并與外部設備通信,依靠驅動程序。設備驅動程序運行在內核空間,作為外部設備與應用軟件橋梁。在所有嵌入式操作系統里,嵌入式Linux 系統相比于其他的系統,在嵌入式領域有著獨特的優勢。首先是Linux 開源免費;然后是Linux 的內核體積小且易于模塊化,適應性和可配置性好適合各種平臺,它同時還支持多任務、多用戶;最后是Linux 有很多開發論壇,提供豐富開發資料,對開發者而言是強大的技術外援。所以本論文是基于Linux 操作系統上開發字符設備驅動程序。
1.1.1 創建設備節點。在Linux 操作系統中所有設備都當作文件來處理,每個設備在/dev 目錄下都有一個設備文件與之相對應,對設備的打開、讀寫、控制和關閉等所有操作都是通過/dev/目錄下對應的文件進行操作。設備節點有時會自動創建,可是字符設備驅動并不直接負責這一項操作。因此我們在設計字符設備驅動時會需要手動創建節點,使用mknod 命令在文件系統上人工創建。除此之外Linux 中有一組函數可以用來在/ dev目錄下創建設備節點,即class_create ( ) 和device_create ( )。1.1.2 主次設備號。Linux 管理的所有設備都有與之對應的目錄,內核通過驅動程序來識別設備。一般來說驅動程序通過主設備號快速匹配外部設備,但同一類設備數量不只一個(或者說一個驅動程序可以同時匹配多個設備),所以必須增加次設備號,它給驅動程序提供了一種能從同一驅動管理下的同類型設備分辨出目標設備的方法。1.1.3 用戶空間和內核空間。嵌入式系統屬于多用戶、多任務操作系統,不能因為某個用戶或某個任務的非法操作造成死機現象,所以用程序運行在用戶空間,而驅動程序則運行在內核空間,內核空間維護計算機系統全局穩定性,驅動程序運行時受到內核程序較多約束,因為在內核中運行任一程序出現問題都會造成計算機系統死機。而應用程序運行較“寬松”。1.1.4 應用程序與硬件設備的訪問。計算機系統中的應用程序通過運行在內核空間的驅動程序來訪問計算機外部設備。應用程序按照如圖1 所示的流程對硬件設備進行訪問。首先是應用程序調用操作系統提供的系統函數,從而訪問內核空間,然后內核空間的結構file_operations 來實現驅動程序中的相關函數,從而實現對設備的訪問。

圖1 應用程序到硬件設備的訪問
要實現用戶空間對內核空間的調用,必須依賴Linux 操作系統內核中一個非常重要的數據結構:file_operations。此結構存放在內核include/linux/fs.h 文件中,所以用到此結構的代碼都應包含此頭文件#include <linux/fs.h>。file_operations 結構如下:


Linux 使用 file_operations 訪問驅動中的函數時,file_operations 中存儲著對設備進行各種操作的函數指針f_ops,file_operations 中每一個成員名都對應一個調用函數,如:file_open( )、file_allocate( )、file_read( )、file_write( )、file_ioctl( )、file_close( )等。比如在對系統進行數據存取的時候,系統通過設備的設備號來找到驅動,然后讀取驅動,開始執行函數。例如:應用程序要對某個外部設備進行如open 操作時,這時匹配該外部設備的驅動程序就會執行對應的fopen 函數。
字符設備驅動程序開發涉及到知識點較多,開發起來顯得有點復雜。但規律可循,總結如下流程:
第一步:編寫驅動程序文件
準備工作(定義設備名稱、定義主次設備號)、設備注冊、定義結構體file_operations、實現結構體內的功能函數、設備注銷等。具體下來有以下工作:a.初始化外部設備的相關寄存器。包括定時寄存器、中斷寄存器、串口寄存器;b.初始化硬件設備參數;c.注冊設備。通過主次設備號與次設備號將驅動程序與設備關聯起來,內核會調用函數register_chrdev 來注冊匹配的外部設備;d.注冊外部設備中斷函數。內核會調用函數request_irq( )來注冊匹配的外部設備的中斷函數;
第二步:驅動程序放進Linux 內核
將編輯好驅動程序源文件和頭文件放置內核相對應的文件下./kernel/drivers/char,同時修改Linux 內核配置文件***.config,在使用make menuconfig 命令時在配置頁面里出現相應的配置選項,使用空格鍵選中,保存后退出,再使用預安裝好的交叉編譯工具鏈進行交叉編譯。需要說明的,設備驅動程序編譯有兩種方法,一種是編譯進內核,另一種是編譯成模塊。一般來說,調試階段編譯成模塊形式,驅動程序穩定后,編譯進內核。修改內核配置文件如下:
a.修改Makefile 文件。
在kernel/drivers/char 目錄下
的Makefile 文件中填加如下代碼,編譯后會生成DEVICE_DRIVER.o 文件:

DEVICE_DRIVER.o
b.修改配置菜單
在Linux 內核對應的目錄下kernel/drivers/char 修改配置文件config.in。在comment 'Character devices' 下面添加。運行make menuconfig 命令時,選中support for DEVICE_DRIVER,編譯后則選中的驅動程序就會編譯進內核:
bool'supportforDEVICE_DRIVER'CONFIG_DEVICE_DRIVER
第三步:交叉編譯
在kernel/目錄下使用如下命令進行交叉編譯。
make dep
make clean
Make zImage
第四步:下載燒錄
使用相關應用軟件將新的內樣鏡像文件下載燒錄到板載Flash 內,或將驅動程序模塊鏡像使用插入的方法到嵌入式平臺。插入命令:insmod device_driver.o。再使用命令創設備節點:mknod /dev/device_name c 50 0。
在Linux 環境下,以鍵盤驅動程序為例進行說明。硬件基本情況是:S3C2410+HD7279(鍵盤數碼管模塊)。
a.編寫file_operations 結構。

d.初始化鍵盤硬件函數。

設備驅動編譯后,接著編寫測試程序kbd.c 用來檢測驅動程序的效果。
fd = open("/dev/Kbd7279", 0)
本論文講述了字符設備驅動的基本原理及編寫字符設備驅動程序的方法。基于S3C2410+HD7279 平臺上,演示了鍵盤字符設備驅動程序開發并進行了驗證。本文可認為是字符設備驅動開發范例,為初學字符設備驅動開發提供參考。