嵌入式系統中,操作系統是通過各種驅動程序來駕馭硬件設備的。設備驅動程序是操作系統內核和硬件設備之間的接口,它為應用程序屏蔽了硬件的細節,這樣在應用程序看來,硬件設備只是一個設備文件,可以像操作普通文件一樣對硬件設備進行操作。設備驅動程序是內核的一部分,完成以下功能:
“
· 驅動程序的注冊和注銷。
· 設備的打開和釋放。
· 設備的讀寫操作。
· 設備的控制操作。
· 設備的中斷和輪詢處理。
Linux主要將設備分為三類:字符設備、塊設備和網絡設備。字符設備是指發送和接收數據以字符的形式進行,沒有緩沖區的設備;塊設備是指發送和接收數據以整個數據緩沖區的形式進行的設備;網絡設備是指網絡設備訪問的BSD socket 接口。下面以字符設備為例,寫出其驅動編寫框架:
一、 編寫驅動程序初始化函數
驅動程序的初始化在函數xxx_init()中完成,包括對硬件初始化、中斷函數、向內核注冊驅動程序等。
首先理解硬件結構,搞清楚其功能,接口寄存器以及CPU怎么訪問控制這些寄存器等。
其次向內核注冊驅動程序。設備驅動程序可以直接編譯進內核,在系統啟動的時候初始化,也可以在需要的時候以模塊的方式動態加載到內核中去。每個字符設備或是塊設備都是通過register_chrdev()函數注冊,調用該函數后就可以向系統申請主設備號,操作成功,設備名就會出現在/proc/devices里。
此外,在關閉設備時,需要先解除原先設備的注冊,需要有清除函數,在xxx_exit()中通過unregister_chrdev()函數在實現,此后設備就會從/proc/devices里消失。
當驅動程序被編譯成模塊時,使用insmod加載模塊,模塊的初始化函數xxx_init()被調用,向內核注冊驅動程序;使用rmmod卸載模塊,模塊的清除函數xxx_exit()被調用。
二、 構造file_operations結構中要用到的各個成員函數
Linux操作系統將所有的設備都看成文件,以操作文件的方式訪問設備。應用程序不能直接操作硬件,使用統一的接口函數調用硬件驅動程序,這組接口被成為系統調用。每個系統調用中都有一個與之對應的函數(open、release、read、write、ioctl等),在字符驅動程序中,這些函數集合在一個file_operations類型的數據結構中。以一個鍵盤驅動程序為例:
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()的用法與具體設備密切相關。以鍵盤Key7279_Ioctl為例:
static int Key7279_Ioctl(struct inode *inode,struct file *file,unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case Key7279_GETKEY:
return key7279_getkey();
default:
printk("Unkown Keyboard Command ID.\n");
}
return 0;
}
cmd的取值及含義都與具體的設備有關,除了ioctl(),設備驅動程序還可能有其他控制函數,比如llseek()等。
當應用程序使用open、release等函數打開某個設備時,設備驅動程序的file_operations結構中的相應成員就會被調用。
三、設備的中斷和輪詢處理
對于不支持中斷的設備,讀寫時需要輪詢設備狀態,以及是否需要繼續進行數據傳輸。例如,打印機。如果設備支持中斷,則可按照中斷方式進行。
模塊在使用中斷前要先請求一個中斷通道(或者 IRQ中斷請求),并在使用后釋放它。通過request_irq()函數來注冊中斷,free_irq()函數來釋放。
四、驅動程序的測試
對驅動程序的調試可以通過打印的方式來進行,就是通過在驅動程序中添加printk()打印函數,來跟蹤驅動程序的執行過程,以此來判斷問題。
以上是我根據自己的學習總結的,可能寫的比較簡單,對于比較復雜的驅動函數,會添加更多的函數,但是大體的框架就是這樣了。
基于操作系統的驅動就是在無操作系統下的硬件接口函數加上操作系統外套
實現一個嵌入式Linux設備驅動程序的大致流程如下:
(l)查看原理圖,理解設備的工作原理。
(2)定義主設備號。設備由一個主設備號和一個次設備號來標識。主設備號唯一標識了設
備類型,即設備驅動程序類型,它是塊設備表或字符設備表中設備表項的索引。次設備號僅
由設備驅動程序解釋,區分被一個設備驅動控制下的某個獨立的設備。
(3)實現初始化函數。在驅動程序中實現驅動的注冊和卸載。
(4)設計所要實現的文件操作,定義file--operations結構。
(5)實現所需的文件操作調用,如read,write等。
(6)實現中斷服務,并用request--irq向內核注冊,中斷并不是每個設備驅動所必需的。
(7)編譯該驅動程序到內核中,或者用insmod命令加載模塊。
(8)測試該設備,編寫應用程序,對驅動程序進行測試。
典型字符設備驅動編寫框架:
1 編寫硬件接口函數
2 建立文件系統與設備驅動程序間的接口,如:struct file_operations結構體
3 注冊設備到chrdevfs全局數組中,注冊或注銷設備可以在任何時候,但一般在模塊加載時注冊設備,在模塊退出時注銷設備。(module_init();module_exit();)
4 以模塊方式編譯驅動源碼,并將其加載到內核中
5 創建設備節點,mknode
6 編寫應用程序訪問底層設備
想要了解嵌入式、物聯網相關技術的可以聯系宋工企鵝號三五二四六五九零八八Tel:173--1795--1908
|