新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > linux 基礎(chǔ)復(fù)習(9)設(shè)備驅(qū)動入門

        linux 基礎(chǔ)復(fù)習(9)設(shè)備驅(qū)動入門

        作者: 時間:2016-10-08 來源:網(wǎng)絡(luò) 收藏

        struct inode提供了關(guān)于設(shè)備文件/dev/driver(假設(shè)此設(shè)備名為driver)的信息。struct file 提供關(guān)于被打開的文件信息,主要用于與文件系統(tǒng)對應(yīng)的設(shè)備驅(qū)動程序使用。struct file 較為重要,這里列出了它的定義:

        struct file {

        mode_t f_mode;/*標識文件是否可讀或可寫,F(xiàn)MODE_READ或FMODE_WRITE*/

        dev_t f_rdev; /* 用于/dev/tty */

        off_t f_pos; /* 當前文件位移 */

        unsigned short f_flags; /* 文件標志,如O_RDONLY、O_NONBLOCK和O_SYNC */

        unsigned short f_count; /* 打開的文件數(shù)目 */

        unsigned short f_reada;

        struct inode *f_inode; /*指向inode的結(jié)構(gòu)指針 */

        struct file_operations *f_op;/* 文件索引指針 */

        };

        設(shè)備驅(qū)動程序主要組成

        (1)設(shè)備注冊

        設(shè)備注冊使用函數(shù)register_chrdev,調(diào)用該函數(shù)后就可以向系統(tǒng)申請主設(shè)備號,如果register_chrdev操作成功,設(shè)備名就會出現(xiàn)在/proc/devices 文件里。

        register_chrdev等函數(shù)語法要點所需頭文件 #i nclude 函數(shù)原型 int register_chrdev(unsigned int major, const char *name,struct file_operations *fops) major:設(shè)備驅(qū)動程序向系統(tǒng)申請的主設(shè)備號 如果為0 則系統(tǒng)為此驅(qū)動程序動態(tài)地分配一個主設(shè)備號函數(shù)傳入值 name:設(shè)備名 fops:對各個調(diào)用的入口點函數(shù)返回值 成功:如果是動態(tài)分配主設(shè)備號,此返回所分配的主設(shè)備號 且設(shè)備名就會出現(xiàn)在/proc/devices文函數(shù)返回值 件里

        出錯:-1

        (2)設(shè)備解除注冊

        在關(guān)閉設(shè)備時,通常需要解除原先的設(shè)備注冊,此時可使用函數(shù)unregister_chrdev,此后該設(shè)備就會從/proc/devices 里消失。

        unregister_chrdev等函數(shù)語法要點

        所需頭文件 #i nclude

        函數(shù)原型 int unregister_chrdev(unsigned int major, const char *name)

        major:設(shè)備的主設(shè)備號,必須和注冊時的主設(shè)備號相同。

        函數(shù)傳入值 name:設(shè)備名

        函數(shù)返回值 成功:0,且設(shè)備名從/proc/devices文件里消失。

        出錯:-1

        (3)打開設(shè)備

        打開設(shè)備的接口函數(shù)是open,根據(jù)設(shè)備的不同,open函數(shù)完成的功能也有所不同,但通常情況下在open函數(shù)中要完成如下工作。

        · 遞增計數(shù)器。

        · 檢查特定設(shè)備的特殊情況。

        · 初始化設(shè)備。

        · 識別次設(shè)備號

        其中遞增計數(shù)器是用于設(shè)備計數(shù)的。由于設(shè)備在使用時通常會打開較多次數(shù),也可以由不同的進程所使用,所以若有一進程想要關(guān)閉該設(shè)備,則必須保證其他設(shè)備沒有使用該設(shè)備。因此使用計數(shù)器就可以很好地完成這項功能。

        這里,實現(xiàn)計數(shù)器操作的是用在中定義的3 個宏如下。

        · MOD_INC_USE_COUNT:計數(shù)器加一。

        · MOD_DEC_USE_COUNT:計數(shù)器減一。

        · MOD_IN_USE:計數(shù)器非零時返回真。

        另外,當有多個物理設(shè)備時,就需要識別次設(shè)備號來對各個不同的設(shè)備進行不同的操作,在有些驅(qū)動程序中并不需要用到。

        雖然這是對設(shè)備文件執(zhí)行的第一個操作,但卻不是驅(qū)動程序一定要聲明的操作。若這個函數(shù)的入口為NULL,那么設(shè)備的打開操作將永遠成功,但系統(tǒng)不會通知驅(qū)動程序。

        (4)釋放設(shè)備

        釋放設(shè)備的接口函數(shù)是release。要注意釋放設(shè)備和關(guān)閉設(shè)備是完全不同的。當一個進程釋放設(shè)備時,其他進程還能繼續(xù)使用該設(shè)備,只是該進程暫時停止對該設(shè)備的使用;而當一個進程關(guān)閉設(shè)備時,其他進程必須重新打開此設(shè)備才能使用。

        釋放設(shè)備時要完成的工作如下。

        · 遞減計數(shù)器MOD_DEC_USE_COUNT。

        · 在最后一次釋放設(shè)備操作時關(guān)閉設(shè)備。

        (5)讀寫設(shè)備

        讀寫設(shè)備的主要任務(wù)就是把內(nèi)核空間的數(shù)據(jù)復(fù)制到用戶空間,或者從用戶空間復(fù)制到內(nèi)核空間,也就是將內(nèi)核空間緩沖區(qū)里的數(shù)據(jù)復(fù)制到用戶空間的緩沖區(qū)中或者相反。這里首先解釋一個read和write函數(shù)的入口函數(shù),如下表所示。

        read、write函數(shù)語法要點

        所需頭文件 #i nclude

        函數(shù)原型 ssize_t (*read) (struct file *filp, char *buff, size_t count, loff_t *offp)

        ssize_t (*write) (struct file *filp, const char *buff, size_t count, loff_t *offp)

        filp:文件指針

        函數(shù)傳入值 buff:指向用戶緩沖區(qū)

        count:傳入的數(shù)據(jù)長度

        offp:用戶在文件中的位置

        函數(shù)返回值 成功:寫入的數(shù)據(jù)長度

        雖然這個過程看起來很簡單,但是內(nèi)核空間地址和應(yīng)用空間地址是有很大區(qū)別的,其中之一就是用戶空間的內(nèi)存是可以被換出的,因此可能會出現(xiàn)頁面失效等情況。所以就不能使用諸如memcpy 之類的函數(shù)來完成這樣的操作。在這里就要使用copy_to_user 或copy_from_user 函數(shù),它們就是用來實現(xiàn)用戶空間和內(nèi)核空間的數(shù)據(jù)交換的。copy_to_user 和copy_from_user 的格式如下表

        所需頭文件 #i nclude

        函數(shù)原型 Unsigned long copy_to_user(void *to, const void *from, unsigned long count)

        Unsigned long copy_from_user(void *to, const void *from, unsigned long count)

        To:數(shù)據(jù)目的緩沖區(qū)

        函數(shù)傳入值 From:數(shù)據(jù)源函數(shù)傳入值 緩沖區(qū)

        count:數(shù)據(jù)長度

        函數(shù)返回值 成功:寫入的數(shù)據(jù)長度

        失?。?EFAULT

        這兩個函數(shù)不僅實現(xiàn)了用戶空間和內(nèi)核空間的數(shù)據(jù)轉(zhuǎn)換,而且還會檢查用戶空間指針的有效性。如果指針無效,那么就不進行復(fù)制

        (6)獲取內(nèi)存

        在應(yīng)用程序中獲取內(nèi)存通常使用函數(shù)malloc,但在設(shè)備驅(qū)動程序中動態(tài)開辟內(nèi)存可以有基于內(nèi)存地址和基于頁面為單位兩類。其中,基于內(nèi)存地址的函數(shù)有kmalloc,注意的是,kmalloc函數(shù)返回的是物理地址,而malloc 等返回的是線性地址,因此在驅(qū)動程序中不能使用malloc函數(shù)。與malloc()不同,kmalloc()申請空間有大小限制。長度是2的整次方,并且不會對所獲取的內(nèi)存空間清零。

        基于頁為單位的內(nèi)存有函數(shù)族有如下。

        · get_zeroed_page:獲得一個已清零頁面。



        關(guān)鍵詞:

        評論


        相關(guān)推薦

        技術(shù)專區(qū)

        關(guān)閉
        主站蜘蛛池模板: 西平县| 新巴尔虎左旗| 扎囊县| 平谷区| 赤城县| 西吉县| 沐川县| 黄冈市| 平安县| 原阳县| 得荣县| 巨鹿县| 娄烦县| 高邮市| 遂平县| 宁海县| 张家川| 乳源| 乃东县| 武冈市| 乌审旗| 积石山| 丹江口市| 扎赉特旗| 锦屏县| 临沂市| 于田县| 炎陵县| 天祝| 东海县| 丹寨县| 铜陵市| 治县。| 旺苍县| 大化| 鄂温| 随州市| 祁门县| 兰溪市| 临城县| 库伦旗|