從上文中可知,在Linux用戶空間中,如若需要操作硬件設(shè)備,均通過/dev目錄下的設(shè)備文件節(jié)點進行操作,基本上每一種設(shè)備都會存在一個或者多個的設(shè)備節(jié)點。
并且在Linux內(nèi)核中,其表示字符設(shè)備的結(jié)構(gòu)成員也提供了相應(yīng)的設(shè)備號。
設(shè)備號成員為dev_t dev;那么其與設(shè)備之間的關(guān)系是什么呢?它又與用戶空間的操作是和關(guān)系??
一、設(shè)備號
那么設(shè)備文件節(jié)點又是如何與Linux內(nèi)核驅(qū)動程序進行對應(yīng)的映射關(guān)系呢???答案是:主設(shè)備號。
在前文舉例過,可能會存在多個相同的設(shè)備運行在Linux系統(tǒng)中,這些設(shè)備所使用的是同一個內(nèi)核驅(qū)動程序,那么是如何區(qū)分各個設(shè)備的呢???答案是:次設(shè)備號。
那么設(shè)備號在用戶空間中,是如何體現(xiàn)的呢???
在我們現(xiàn)有的Linux系統(tǒng)中,進行/dev目錄下,執(zhí)行命令。
命令:ls -l
如上圖所示,在其設(shè)備節(jié)點文件的屬性中,可以查看到設(shè)備節(jié)點的主設(shè)備號和次設(shè)備號。其中逗號‘,’前為主設(shè)備號,后為次設(shè)備號。并且如上圖所示,對于loop設(shè)備而言,其有很多相同的設(shè)備運行在Linux操作系統(tǒng)中,那么他們的各個相同的設(shè)備都具有唯一的節(jié)點名稱,但他們的主設(shè)備號相同,均為7;次設(shè)備號不同,按照節(jié)點的順序進行排列。
二、設(shè)備號操作
在Linux內(nèi)核源碼中,使用結(jié)構(gòu)體dev_t類型來定義設(shè)備號。實際上dev_t類型為32位的unsigned int類型(在Linux內(nèi)核源碼中可以進行跟蹤)。其中高12位作為存儲主設(shè)備號,低20位作為存儲次設(shè)備號。
那么就存在了如下幾個問題:
1.如果知道主設(shè)備號和次設(shè)備號,那么怎么組合成dev_t類型的數(shù)據(jù)?
在Linux內(nèi)核中,提供了MKDEV方法宏來進行組合主設(shè)備號和次設(shè)備號。其原型如下:
用法為:dev_t dev = MKDEV(主設(shè)備號,次設(shè)備號)
2.如何從dev_t類型的數(shù)據(jù)中解析出主設(shè)備號?
如上圖,在Linux內(nèi)核中采用了MAJOR方法宏來進行解析主設(shè)備號。用法如下:
主設(shè)備號 = MAJOR(dev_t dev)
3.如何從dev_t類型的數(shù)據(jù)中解析出次設(shè)備號?
如上圖,在Linux內(nèi)核中采用了MINOR方法宏來進行解析主設(shè)備號。用法如下:
次設(shè)備號 = MINOR(dev_t dev)
三、設(shè)備號分配/申請
因為是在Linux內(nèi)核框架下進行編寫設(shè)備驅(qū)動程序,那么每一個設(shè)備的設(shè)備號可以有Linux內(nèi)核提供的方法來進行分配。
Linux內(nèi)核中如何為設(shè)備分配一個主設(shè)備號???
實際上在Linux內(nèi)核中提供了兩種方法可以進行分配主設(shè)備號。分別為靜態(tài)申請設(shè)備號和動態(tài)分配設(shè)備號。
靜態(tài)申請設(shè)備號:程序員自己選擇一個數(shù)字作為某一個設(shè)備的主設(shè)備號,再確定其次設(shè)備號(實際上如果是單一的設(shè)備,通常次設(shè)備號為0),通過組合得到設(shè)備號,然后通過函數(shù)register_chrdev_region向內(nèi)核申請主設(shè)備號使用。其原型如下:
靜態(tài)申請設(shè)備號的缺點在于,如果所申請的設(shè)備號已經(jīng)在內(nèi)核中被其他設(shè)備驅(qū)動使用了,則會申請失敗。并且另一點是,在Linux內(nèi)核中存在一些設(shè)備驅(qū)動的設(shè)備號為固定的設(shè)備號,例如:串口UART、I2C設(shè)備驅(qū)動等。
動態(tài)分配設(shè)備號:Linux內(nèi)核提供方法函數(shù)alloc_chrdev_region,由內(nèi)核動態(tài)的分配一個可用的主設(shè)備號給相應(yīng)的設(shè)備驅(qū)動。其原型為:
動態(tài)分配設(shè)備號的優(yōu)點在于,因為Linux內(nèi)核本身自己知道了哪些設(shè)備號已經(jīng)被使用了,所以基本不會導致分配到已用了的設(shè)備號,從而不會申請設(shè)備號失敗。
四、設(shè)備號注銷
實際上無論是使用動態(tài)分配得到的設(shè)備號,還是使用靜態(tài)申請得到的設(shè)備號,當Linux系統(tǒng)中不再需要相應(yīng)的硬件設(shè)備時,可將其設(shè)備驅(qū)動進行注銷,那么重要的一步就是在設(shè)備驅(qū)動退出時,使用方法函數(shù)unregister_chrdev_region函數(shù)釋放相應(yīng)的設(shè)備號。其原型為:
設(shè)備號釋放后,設(shè)備節(jié)點文件將不存在。