當(dāng)前位置:首頁 > 嵌入式培訓(xùn) > 嵌入式學(xué)習(xí) > 講師博文 > Linux字符設(shè)備驅(qū)動(dòng)模型之設(shè)備號
Linux字符設(shè)備驅(qū)動(dòng)模型之設(shè)備號
時(shí)間:2018-09-27 來源:未知
從上文中可知,在Linux用戶空間中,如若需要操作硬件設(shè)備,均通過/dev目錄下的設(shè)備文件節(jié)點(diǎn)進(jìn)行操作,基本上每一種設(shè)備都會(huì)存在一個(gè)或者多個(gè)的設(shè)備節(jié)點(diǎn)。
并且在Linux內(nèi)核中,其表示字符設(shè)備的結(jié)構(gòu)成員也提供了相應(yīng)的設(shè)備號。

設(shè)備號成員為dev_t dev;那么其與設(shè)備之間的關(guān)系是什么呢?它又與用戶空間的操作是和關(guān)系??
一、設(shè)備號
那么設(shè)備文件節(jié)點(diǎn)又是如何與Linux內(nèi)核驅(qū)動(dòng)程序進(jìn)行對應(yīng)的映射關(guān)系呢???答案是:主設(shè)備號。

在前文舉例過,可能會(huì)存在多個(gè)相同的設(shè)備運(yùn)行在Linux系統(tǒng)中,這些設(shè)備所使用的是同一個(gè)內(nèi)核驅(qū)動(dòng)程序,那么是如何區(qū)分各個(gè)設(shè)備的呢???答案是:次設(shè)備號。

那么設(shè)備號在用戶空間中,是如何體現(xiàn)的呢???
在我們現(xiàn)有的Linux系統(tǒng)中,進(jìn)行/dev目錄下,執(zhí)行命令。
命令:ls -l

如上圖所示,在其設(shè)備節(jié)點(diǎn)文件的屬性中,可以查看到設(shè)備節(jié)點(diǎn)的主設(shè)備號和次設(shè)備號。其中逗號‘,’前為主設(shè)備號,后為次設(shè)備號。并且如上圖所示,對于loop設(shè)備而言,其有很多相同的設(shè)備運(yùn)行在Linux操作系統(tǒng)中,那么他們的各個(gè)相同的設(shè)備都具有唯一的節(jié)點(diǎn)名稱,但他們的主設(shè)備號相同,均為7;次設(shè)備號不同,按照節(jié)點(diǎn)的順序進(jìn)行排列。
二、設(shè)備號操作
在Linux內(nèi)核源碼中,使用結(jié)構(gòu)體dev_t類型來定義設(shè)備號。實(shí)際上dev_t類型為32位的unsigned int類型(在Linux內(nèi)核源碼中可以進(jìn)行跟蹤)。其中高12位作為存儲主設(shè)備號,低20位作為存儲次設(shè)備號。
那么就存在了如下幾個(gè)問題:
1.如果知道主設(shè)備號和次設(shè)備號,那么怎么組合成dev_t類型的數(shù)據(jù)?
在Linux內(nèi)核中,提供了MKDEV方法宏來進(jìn)行組合主設(shè)備號和次設(shè)備號。其原型如下:

用法為:dev_t dev = MKDEV(主設(shè)備號,次設(shè)備號)
2.如何從dev_t類型的數(shù)據(jù)中解析出主設(shè)備號?
如上圖,在Linux內(nèi)核中采用了MAJOR方法宏來進(jìn)行解析主設(shè)備號。用法如下:
主設(shè)備號 = MAJOR(dev_t dev)
3.如何從dev_t類型的數(shù)據(jù)中解析出次設(shè)備號?
如上圖,在Linux內(nèi)核中采用了MINOR方法宏來進(jìn)行解析主設(shè)備號。用法如下:
次設(shè)備號 = MINOR(dev_t dev)
三、設(shè)備號分配/申請
因?yàn)槭窃贚inux內(nèi)核框架下進(jìn)行編寫設(shè)備驅(qū)動(dòng)程序,那么每一個(gè)設(shè)備的設(shè)備號可以有Linux內(nèi)核提供的方法來進(jìn)行分配。
Linux內(nèi)核中如何為設(shè)備分配一個(gè)主設(shè)備號???
實(shí)際上在Linux內(nèi)核中提供了兩種方法可以進(jìn)行分配主設(shè)備號。分別為靜態(tài)申請?jiān)O(shè)備號和動(dòng)態(tài)分配設(shè)備號。
靜態(tài)申請?jiān)O(shè)備號:程序員自己選擇一個(gè)數(shù)字作為某一個(gè)設(shè)備的主設(shè)備號,再確定其次設(shè)備號(實(shí)際上如果是單一的設(shè)備,通常次設(shè)備號為0),通過組合得到設(shè)備號,然后通過函數(shù)register_chrdev_region向內(nèi)核申請主設(shè)備號使用。其原型如下:

靜態(tài)申請?jiān)O(shè)備號的缺點(diǎn)在于,如果所申請的設(shè)備號已經(jīng)在內(nèi)核中被其他設(shè)備驅(qū)動(dòng)使用了,則會(huì)申請失敗。并且另一點(diǎn)是,在Linux內(nèi)核中存在一些設(shè)備驅(qū)動(dòng)的設(shè)備號為固定的設(shè)備號,例如:串口UART、I2C設(shè)備驅(qū)動(dòng)等。
動(dòng)態(tài)分配設(shè)備號:Linux內(nèi)核提供方法函數(shù)alloc_chrdev_region,由內(nèi)核動(dòng)態(tài)的分配一個(gè)可用的主設(shè)備號給相應(yīng)的設(shè)備驅(qū)動(dòng)。其原型為:

動(dòng)態(tài)分配設(shè)備號的優(yōu)點(diǎn)在于,因?yàn)長inux內(nèi)核本身自己知道了哪些設(shè)備號已經(jīng)被使用了,所以基本不會(huì)導(dǎo)致分配到已用了的設(shè)備號,從而不會(huì)申請?jiān)O(shè)備號失敗。
四、設(shè)備號注銷
實(shí)際上無論是使用動(dòng)態(tài)分配得到的設(shè)備號,還是使用靜態(tài)申請得到的設(shè)備號,當(dāng)Linux系統(tǒng)中不再需要相應(yīng)的硬件設(shè)備時(shí),可將其設(shè)備驅(qū)動(dòng)進(jìn)行注銷,那么重要的一步就是在設(shè)備驅(qū)動(dòng)退出時(shí),使用方法函數(shù)unregister_chrdev_region函數(shù)釋放相應(yīng)的設(shè)備號。其原型為:

設(shè)備號釋放后,設(shè)備節(jié)點(diǎn)文件將不存在。

