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