1引言
隨著嵌入式系統的發展,嵌入式 Linux以其穩定性和開放源代碼的優點在嵌入式系統的開發中得到廣泛應用。越來越多的軟硬件廠商使用嵌入式 Linux來開發自己的產品,對基于嵌入式 Linux平臺開發設備的驅動程序和應用程序的需求在成倍增長。本文通過實現對 PXA255開發板外圍字符設備(電機、數碼管、串口和 mini鍵盤)的操作和控制,詳細討論了嵌入式 linux字符設備驅動的設計與應用。
2系統的設計框架
系統的設計分為字符設備驅動程序和人機交互界面兩部分。驅動程序為應用程序提供了操作設備的接口;人機交互界面的設計實現設備應用程序并完成人機交互的功能。整個系統軟硬件的關系如圖 1:字符設備被映射到 Linux文件系統的文件和目錄,通過文件系統的系統調用接口 open(),write(),read(),close()等函數訪問字符設備,實現設備的操作。
圖 1 系統軟硬件的關系
3系統字符設備驅動程序的設計方法
Linux驅動程序是設備與具體的應用程序的中間層,它提供操作設備的接口,應用程序員不需要知道具體設備工作細節,只要調用一組標準化的函數就能完成對設備的操作,這些標準化的函數與具體的驅動沒有關系,而將這些函數映射到作用于具體設備上的操作則與驅動程序相關[1]。Linux設備分為字符設備,塊設備和網絡設備,字符設備是能夠像字節流一樣被訪問的設備。以下通過描述字符設備(電動機、數碼管、串口、mini鍵盤)驅動的實現方法,深入討論了基于嵌入式 linux的字符設備驅動的設計方法和實現過程。
3.1初始化函數與清除函數
Linux系統中,設備驅動的初始化函數負責注冊設備,并完成驅動程序必要的初始化以及申請中斷等[2],Linux系統使用 module_init宏指定初始化函數。在初始化函數中調用 regiSTer_chrdev函數向系統注冊字符設備,通過 request_IRq 函數申請中斷。例如電機設備的初始化函數如下:
static int __init moto_init(void){
int ret;
ret = register_chrdev(MOTO_MAJOR, “moto”, &moto_fops);//注冊電機設備
if (ret) {
printk(KERN_ERR “%s: can‘t get major %d.n”,
__func__, MOTO_MAJOR);
return ret;
}
printk(KERN_INFO “%s: register moto device successfully.n”, __func__);
return 0;
} 其中,register_chrdev函數的第一個參數為主設備號,如果為0 則系統為此驅動程序動態地分配一個主設備號;第二個參數是設備名稱,這里是以moto為設備名稱;第三個參數moto_fops是默認的struct file_operations結構體 。
清除函數的功能和初始化函數的功能相反,它將驅動程序所占用的系統資源、中斷號進行釋放。Linux系統使用 module_exit宏指定清除函數。
3.2中斷
在 Linux 系統中,中斷是由系統來管理與維護的。中斷服務子程序在初始化函數中調用 request_irq 函數與相應中斷號關聯,并將該中斷的相關信息添加到系統的中斷信息列表中。中斷發生時, Linux系統響應中斷號來實現中斷處理程序的執行。mini鍵盤按鍵觸發產生中斷號為 SIMPLE_KEY_IRQ的中斷,系統自動檢索并調用鍵盤中斷服務子程序。鍵盤中斷處理流程如圖 2:
3.3 設備驅動接口的實現
在Linux內核中,字符設備使用 struct file_operations結構體來實現設備的各種操作接口,這些操作主要用來實現系統調用,命名為 open、read等等。file_operations結構是定義在 《linux/fs.h》中的函數指針數組,每個設備文件都與它自己的操作函數相關聯。編寫字符設備驅動程序,主要是實現 struct file_operations結構中的各個函數。
本系統各設備驅動的設計主要實現 open、read、write和 release這四個方法接口。 file_operation結構成員如下: /* DEVICE驅動程序設備操作方法集 */ struct file_operations device_fops = {
open方法提供給驅動程序以初始化的能力,從而為以后的操作完成初始化做準備。本系統中存在多個設備共用一個驅動的情況,驅動中的 open方法程序框架如下:
int device_open(struct inode *inode, struct file *filp){ int minor = MINOR(kdev); //次設備號的讀取 switch(minor) {
case first_device: device_first_vaddr = (unsigned long)ioremap (DEVICE_ FIRST _ADDR, 2);
……
case second_device:
……
default:
……
} MOD_INC_USE_COUNT; // 遞增模塊引用計數 , 防止模塊在使用中被卸載 if (down_interruptible(&device_mutex)) { …… }; }
1)open方法調用 MINOR(kdev)宏實現次設備號的讀取,使用 switch語句完成設備的匹配初始化。Linux系統為每一個設備分配了一個主設備號和次設備號。主設備號標識具體的設備驅動程序,次設備號標識具體設備。開發板電機設備有直流電機和步進電機,它們的主設備號都是 252,次設備號分別為 0和 1。數碼管、串口、 mini鍵盤的驅動設計只針對單個設備,次設備號設計為 0。
2)ioremap函數在 open方法中實現對電機、數碼管、串口、mini鍵盤寄存器的訪問。 PXA255處理器有專門的存儲器管理單元(MMU),在驅動中不能直接對設備 I/O內存的物理地址進行讀寫,需要調用ioremap 等內核函數將寄存器的實際物理地址映射到內核統一的地址空間中,從而實現了對物理地址的間接調用。例如寄存器 DEVICE_ FIRST _ADDR的讀寫操作,通過讀寫 device_first_vaddr變量實現。在 asm/arch/pxa-regs.h頭文件中定義了各種寄存器的宏,文件中的宏變量都是經過地址映射的可以直接使用。
release方法的作用正好與 open相反,通過調用 iounmap函數撤銷 device設備的虛擬地址映射,同時釋放互斥鎖,遞減模塊引用計數,當模塊引用計數減到 0時,close函數才能真正的關閉設備。read和 write方法的任務是相似的,主要完成用戶空間和內核空間之間的數據拷貝。
read方法程序框架如下:
ssize_t device_read(struct file *filp, char *buf, size_t count, loff_t *offp){
……
if (copy_to_user(buf, (u8 *)&BUF, count)) { ……} //寫數據給用戶空間
return count; // 返回成功讀取的字節數 }
其中,copy_to_user函數實現內核空間到用戶空間的數據拷貝。應用程序調用該方法接口實現串口數據的接收。
write方法的實現同read方法類似。通過調用 copy_from_user函數實現用戶空間到內核空間的數據拷貝。該方法接口實現串口數據的發送、LED和MOTO控制寄存器的設置。
3.4 驅動的裝載和卸載
Linux驅動程序的編譯加載有兩種方式。一種是編譯成模塊在運行時加載,不需要重新啟動內核,它使用 insmod工具將驅動模塊加載進內核,使用 rmmod從內核中卸載模塊。該方法實現如下:1)編譯驅動并下載驅動到開發板:$ arm-linux-gcc device_driver.c -I /home/eflag/kernel/include/ -c生成 device_driver.o文件,通過 tftp工具下載到開發板;2)驅動的加載:$ insmod device_driver.o。設備驅動的加載成功后,可以編寫應用程序進行設備驅動的檢測;3)驅動的卸載:$ rmmod device_driver。
另一種是將驅動程序靜態編譯進內核,再運行新的內核來測試驅動,該方法是在linux系統字符設備驅動文件夾linux/driver/char/中加入設備驅動源程序,同時修改 makefile文件,重新編譯內核,下載新內核到開發板,系統啟動后自動加載設備驅動 [3]。在驅動加載成功后就可以對該驅動的設備進行讀寫等操作。 4 Qt人機界面的實現
Qt是由 Troolltech公司開發的一套開源圖形用戶界面庫。它給應用程序開發者提供了開發圖形界面所需的各種功能。Qtopia core是嵌入式環境下所使用的 Qt,很多嵌入式產品如 PDA、手機都采用 qtopia core的圖形庫作為人機界面設計的框架。本系統使用 qtopia core的圖形庫進行用戶界面的開發。
4.1 Qt應用程序的設計
Qt的事件驅動機制是 single/slot(信號/槽)機制,通過 connect函數連接控件信號(Single)與槽函數(slot)。首先控件觸發產生 Single信號,然后由 signal信號觸發執行槽函數[4]。本系統中槽函數為具體設備應用程序。
設備應用程序的開發主要是系統函數的調用,如 open(打開設備),read/write(讀寫設備),close(關閉設備)等。本系統設備應用程序開發如下: RS232收發數據功能; LED跑馬燈功能;操控電機轉動功能;mini鍵盤鍵值讀取功能。
Linux系統中設備作為文件被訪問,對設備進行訪問前需建立設備節點:
$mknod /dev/device_name c MAJOR MINOR
其中 device_name是設備節點名, c是字符設備標志, MAJOR是主設備號,MINOR是
次設備號。open函數使用/dev/device_name作為文件路徑來打開設備。
4.2Qt應用程序的運行
1)編譯 Qtopia core應用程序生成可執行文件 application。通過 tftp工具下載可執行文件到開發板;2)開發板中 application可執行文件的運行: $ chomd +x application $ 。/application –qws。
LCD顯示器顯示人機交互界面如圖 3,通過輸入設備如鼠標、鍵盤、觸摸屏可以完成設備的操作。
5 總結
實現了電機、數碼管、串口和 mini鍵盤的驅動程序和應用程序的開發,設計了人機交互界面。
本文創新點:詳細分析了嵌入式 Linux下字符設備驅動程序的構建過程。整個系統的設計和實現過程對嵌入式 Linux系統的開發有一定的參考價值。
評論