嵌入式數(shù)據(jù)采集系統(tǒng)中的ADS8364驅(qū)動(dòng)程序設(shè)計(jì)
4 ADS8364的驅(qū)動(dòng)程序設(shè)計(jì)概述
4.1 驅(qū)動(dòng)程序的LKM實(shí)現(xiàn)機(jī)制
Linux內(nèi)核提供了兩種機(jī)制來(lái)開發(fā)設(shè)備驅(qū)動(dòng)程序,一種是直接把驅(qū)動(dòng)程序編譯進(jìn)內(nèi)核,成為Linux內(nèi)核的一部分。另一種是通過LKM(Loadable Kernel Module,即可加載模塊化機(jī)制)來(lái)開發(fā)可動(dòng)態(tài)加載和卸載的驅(qū)動(dòng)模塊[3]。驅(qū)動(dòng)程序如果編譯進(jìn)內(nèi)核的話,會(huì)增加內(nèi)核的大小,還要改動(dòng)內(nèi)核的源文件,而且不能動(dòng)態(tài)的卸載,不利于調(diào)試,所以本系統(tǒng)把ADS8364的驅(qū)動(dòng)程序編寫成了 LKM型驅(qū)動(dòng)程序(就是把ADS8364的驅(qū)動(dòng)程序作為一個(gè)獨(dú)立的單元模塊,在使用時(shí)可以使用insmod命令加載到核心中,用完后使用rmmod命令卸載的那種)。
4.2 驅(qū)動(dòng)程序的注冊(cè)與注銷
向系統(tǒng)增加一個(gè)驅(qū)動(dòng)程序則意味著要賦予它一個(gè)主設(shè)備號(hào),這一賦值過程是在驅(qū)動(dòng)程序模塊的初始化中完成的。ADS8364的初始化入口函數(shù)定義如下:
int _init ads8364_init_module(void)全功能版J-LINK ARM仿真器V6.0
{ …..
ret = register_chrdev(11, ADS8364, ad_fops);
……}
在用insmod命令將編譯好的模塊調(diào)入內(nèi)存時(shí),ads8364_init_module( )函數(shù)被調(diào)用。在這里,ads8364_init_module( )只做了一件事,它調(diào)用函數(shù)register_chrdev( )向內(nèi)核注冊(cè)該字符設(shè)備。函數(shù)register_chrdev()定義在linux/fs-h> 中。register_chrdev需要三個(gè)參數(shù),參數(shù)一是希望獲得的設(shè)備號(hào),如果是零的話,系統(tǒng)將自動(dòng)選擇一個(gè)沒有被占用的設(shè)備號(hào)作為該字符設(shè)備的主設(shè)備號(hào)并返回。參數(shù)二是設(shè)備文件名,這個(gè)名字必須插入到/dev目錄中,并與驅(qū)動(dòng)程序的主設(shè)備號(hào)和次設(shè)備號(hào)相連。參數(shù)三用來(lái)登記驅(qū)動(dòng)程序?qū)嶋H執(zhí)行操作的函數(shù)的指針。如果登記成功,返回設(shè)備的主設(shè)備號(hào),不成功,返回一個(gè)負(fù)值。在此,我們選用當(dāng)前不用的設(shè)備號(hào)11作為ADS8364的主設(shè)備號(hào),設(shè)備名為 ADS8364。
在關(guān)閉字符設(shè)備或塊設(shè)備時(shí),還需要通過unregister_chrdev( )從內(nèi)核中注銷設(shè)備,并釋放主設(shè)備號(hào)。在用rmmod卸載該驅(qū)動(dòng)模塊時(shí),cleanup_module函數(shù)被調(diào)用,它釋放字符設(shè)備ADS8364在系統(tǒng)字符設(shè)備表中占有的表項(xiàng)。
void ads8364_cleanup_module(void)
{ unregister_chrdev(11, ADS8364); info("ADS8364 cleanup module ok!"); }
4.3 file_operations結(jié)構(gòu)體的設(shè)計(jì)
在Linux中,字符設(shè)備向內(nèi)核提供的接口函數(shù)集就是文件操作集file_operations結(jié)構(gòu)體。在Linux系統(tǒng)中,打開的設(shè)備在內(nèi)核內(nèi)部由設(shè)備文件file結(jié)構(gòu)標(biāo)識(shí),內(nèi)核使用file_operations(文件操作)結(jié)構(gòu)訪問驅(qū)動(dòng)程序的函數(shù)。每個(gè)文件都與自己的函數(shù)集相關(guān)聯(lián)(通過包含指向file_operations結(jié)構(gòu)的f_ops指針段實(shí)現(xiàn)),這些操作主要負(fù)責(zé)系統(tǒng)調(diào)用的實(shí)現(xiàn)[4]。為了使驅(qū)動(dòng)程序在結(jié)構(gòu)的定義發(fā)生變化時(shí)更具可移植性,并且使得代碼更加緊湊且易讀,我們首先采用標(biāo)記化格式聲明ADS8364的file_operations結(jié)構(gòu):
static struct file_operations ad_fops = {全功能版J-LINK ARM仿真器V6.0
owner: THIS_MODULE,/* ad_fops所屬的設(shè)備模塊 */
read:ads8364_read,/*從設(shè)備中讀數(shù)據(jù)*/
poll:ads8364_poll, /*查詢?cè)O(shè)備狀態(tài)*/
ioctl:ads8364_ioctl,/*設(shè)備I/O控制*/全功能版J-LINK ARM仿真器V6.0
open:ads 8364_open,/*打開設(shè)備操作*/
release:ads 8364_release,/*釋放操作*/
};
file_operations結(jié)構(gòu)體把系統(tǒng)調(diào)用和驅(qū)動(dòng)程序關(guān)聯(lián)起來(lái)。這個(gè)結(jié)構(gòu)的每一個(gè)成員的名字都對(duì)應(yīng)著一個(gè)系統(tǒng)調(diào)用。用戶進(jìn)程利用系統(tǒng)調(diào)用在對(duì)設(shè)備文件進(jìn)行諸如read、write、open等操作時(shí),系統(tǒng)調(diào)用通過設(shè)備文件的主設(shè)備號(hào)找到相應(yīng)的設(shè)備驅(qū)動(dòng)程序,然后讀取這個(gè)數(shù)據(jù)結(jié)構(gòu)相應(yīng)的函數(shù)指針,接著把控制權(quán)交給該函數(shù)。這就是ADS8364驅(qū)動(dòng)程序工作的基本原理。既然是這樣,則編寫設(shè)備驅(qū)動(dòng)程序的主要工作就是編寫子函數(shù),并填充 file_operations的各個(gè)域。下面我們就把file_operations的各個(gè)域的功能和主要調(diào)用函數(shù)加以介紹。
1)設(shè)備I/O控制操作函數(shù)
與普通文件相比,設(shè)備文件的操作要復(fù)雜得多,不可能簡(jiǎn)單地通過 read、write 和llseek 等來(lái)實(shí)現(xiàn)。所有其它類型的操作都可以通過VFS的ioctl調(diào)用來(lái)執(zhí)行,函數(shù)定義如下:
static int ads8364_ioctl(struct inode * inode, struct file *filp, unsigned int cmd, unsigned long arg)
ads8364_ioctl是ADS8364驅(qū)動(dòng)程序中對(duì)設(shè)備的I/O通道進(jìn)行管理的函數(shù)。其中參數(shù)inode就是用戶程序打開ADS8364時(shí)使用open函數(shù)返回的文件標(biāo)示符,cmd就是用戶程序?qū)DS8364的控制命令,它是唯一聯(lián)系用戶程序命令和驅(qū)動(dòng)程序支持的途徑,該函數(shù)通過cmd區(qū)分操作,通過arg傳遞參數(shù)和結(jié)果。在驅(qū)動(dòng)程序中實(shí)現(xiàn)的ads8364_ioctl函數(shù)體內(nèi),有一個(gè)switch{case}結(jié)構(gòu),每一個(gè)case對(duì)應(yīng)一個(gè)命令碼,做出一些相應(yīng)的操作。 ads8364_ioctl的設(shè)計(jì)的關(guān)鍵就是,如何將cmd命令碼在用戶程序里生成以及在驅(qū)動(dòng)程序里的解析,所以switch{case}結(jié)構(gòu)在 ads8364_ioctl中至關(guān)重要,因?yàn)閷?duì)設(shè)備的I/O控制都是通過這一部分的代碼實(shí)現(xiàn)的。
linux操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)
評(píng)論