在這裏,以字符設備爲例,分析其驅動程序的框架:
一、編寫驅動程序的初始化函數
驅動程序的初始化在函數XXX_init()中完成,包括對硬件初始化、中斷函數、向內核註冊等。
a) 首先要理解硬件結構,搞清楚其功能、接口寄存器以及CPU怎麼訪問控制這些寄存器等。
b) 其次要明白如何把該設備驅動註冊到內核中。設備驅動程序可以直接編進內核(在移植內核時,就將該驅動程序編譯進內核),在系統啓動的時候初始化,也可以在需要的時候以模塊的方式動態到內核中去(使用insmod加載模塊到內核中,而移除模塊使用rmmod卸載模塊)。每個字符設備或是塊設備都是通過register_chrdev()函數註冊,調用該函數後就可以向系統申請主設備號,操作成功後,該設備名就會出現在/proc/devices裏。
此外,在關閉設備時,需要先解除原先設備的註冊,而解除註冊功能在XXXX_exit()中通過unregister_chrdev()函數實現,之後設備就會從/proc/devices裏消失。
二、構造file_perations結構中要用到各個成員函數
Linux操作系統將所有的設備都要看成文件,並以操作文件的方式訪問設備。應用程序不能直接操作硬件,而是使用統一的接口調用硬件驅動程序,這組接口被看成系統調用。每個系統調用中都有一個與之對應的函數(open、release、read、write、ioctl等),在字符驅動程序中,這些函數集合在一個file_openrations類型的數據結構中。以一個鍵盤驅動程序爲例:
Struct file_operations Key7279_fops =
{
.open = Key7279_open,
.ioctl =Key7279_ioctl,
.release=Key7279_close,
.read=Key7279_read,
};
1、設備的打開與釋放
打開設備是由open()函數來完成,在open()函數中主要使用硬件的寄存器接口,對硬件進行初始化的設置工作。
而釋放設備由release()函數完成。在release()函數中主要使用硬件的寄存器接口,對硬件進行關閉操作。
2、設備的讀寫操作
讀寫設備的主要任務就是把內核空間的數據複製到用戶空間,或者是從用戶空間複製到內核空間,也就是將內核空間緩衝區裏的數據複製到用戶空間的緩衝區中或者相反。字符設備使用各自的read()函數和write()函數來進行數據讀寫。
3、設備的控制操作
大部分設備除了讀寫能力,還可經行超出簡單的數據傳輸之外的操作,所以設備驅動也必須具備進行各種硬件控制操作的能力,這些操作常常通過ioctl方法來支持。與讀寫操作不同,ioctl()的用法與具體設備密切相關。
三、設備的中斷和輪詢處理
對於不支持中斷的設備,讀寫時需要輪詢設備狀態,以及是否需要繼續進行數據傳輸。例如,打印機。如果設備支持中斷,則可按照中斷方式進行。
模塊在使用中斷前要先請求一箇中斷通道(或者 IRQ中斷請求),並在使用後釋放它。通過request_irq()函數來註冊中斷,free_irq()函數來釋放。
四、驅動程序的測試
對驅動程序的調試可以通過打印的方式來進行,就是通過在驅動程序中添加printk()打印函數,來跟蹤驅動程序的執行過程,以此來判斷問題。
基於操作系統的驅動就是在無操作系統下的硬件接口函數加上操作系統
典型字符設備驅動編寫框架:
1 編寫硬件接口函數
2 建立文件系統與設備驅動程序間的接口,如:struct file_operations結構體
3 註冊設備到chrdevfs全局數組中,註冊或註銷設備可以在任何時候,但一般在模塊加載時註冊設備,在模塊退出時註銷設備。(module_init();module_exit();)
4 以模塊方式編譯驅動源碼,並將其加載到內核中
5 創建設備節點,mknode