Linux設備驅動程序 之 主次設備號


主設備號和次設備號

對字符設備的訪問是通過文件系統內的設備名稱進行的,這些名稱被稱為特殊文件、設備文件、或者簡單稱之為文件系統樹的節點,它們通常位於/dev目錄。字符設備驅動程序的設備文件可以通過ls -l命令輸出的第一列中的c字符來識別,塊設備也出現在/dev下,但它們由字符b來標識;

通過執行ls -l 命令,可以看到在修改日期之前,有兩個用逗號分隔的數字,分別為主設備號和次設備號。

主設備號標識設備對應的驅動程序;linux設備內核允許多個驅動程序共享主設備號;

次設備號由內核使用,用用戶正確確定設備文件所指的設備。依賴驅動程序的編寫方式,我們可以通過次設備號獲得一個指向內核設備的直接指針,也可以將次設備號當做設備本地數組的索引。不管哪種方式,除了知道次設備號用來指向驅動程序所實現的設備之外,內核本身不關心關於此設備號的其他信息;

crw-rw----. 1 root video    10, 175 Nov 25 17:09 agpgart
crw-------. 1 root root     10, 235 Nov 25 17:09 autofs
drwxr-xr-x. 2 root root         140 Nov 25 17:09 block
drwxr-xr-x. 2 root root          80 Nov 25 17:09 bsg
crw-------. 1 root root     10, 234 Nov 25 17:09 btrfs-control
drwxr-xr-x. 3 root root          60 Nov 25 17:09 bus
lrwxrwxrwx. 1 root root           3 Nov 25 17:09 cdrom -> sr0
drwxr-xr-x. 2 root root        3120 Nov 25 17:10 char
crw-------. 1 root root      5,   1 Nov 25 17:09 console
lrwxrwxrwx. 1 root root          11 Nov 25 17:09 core -> /proc/kcore
drwxr-xr-x. 6 root root         120 Nov 25 17:09 cpu
crw-------. 1 root root     10,  62 Nov 25 17:09 cpu_dma_latency
crw-------. 1 root root     10, 203 Nov 25 17:09 cuse
drwxr-xr-x. 5 root root         100 Nov 25 17:09 disk
crw-rw----+ 1 root audio    14,   9 Nov 25 17:09 dmmidi

 

設備編號的內部表達

內核中,dev_t類型(位於<linux/types.h>)用來保存設備編號,包括主設備號和次設備號;

1 typedef __u32 __kernel_dev_t;
2 
3 typedef __kernel_dev_t        dev_t;

可見dev_t類型是個32位的無符號整數,其中12位用來表示主設備號,其余20位表示次設備號;我們不應該對設備編號的組織做假定,而應該始終使用如下兩個宏(位於linux/kdev_t.h)來獲取主次設備號;

 

1 #define MINORBITS    20
2 #define MINORMASK    ((1U << MINORBITS) - 1)
3 
4 #define MAJOR(dev)    ((unsigned int) ((dev) >> MINORBITS))
5 #define MINOR(dev)    ((unsigned int) ((dev) & MINORMASK))

如果需要將主次設備號轉換成dev_t類型,則使用下面宏(位於linux/kdev_t.h):

1 #define MKDEV(ma,mi)    (((ma) << MINORBITS) | (mi))

 

分配和釋放設備編號

指定范圍分配編號:

在建立一個字符設備之前,我們的驅動程序首先要做的事情就是獲取一個或者多個設備編號,完成該工作的必要函數是register_chrdev_region,該函數在<linux/fs.h>中聲明:

1 int register_chrdev_region(dev_t from, unsigned count, const char *name)

參數from標識要分配的設備號范圍的起始值,次設備號經常設置為0,但對該函數不是必須的;

參數count標識分配設備號的個數,如果count非常大,則所請求的范圍可能和下一個主設備號重疊,但是只要我們所請求的編號范圍是可用的,則不會帶來問題;

參數name是和該編號范圍關聯的設備名稱,它將出現在/proc/devices和sysfs中;

動態分配設備編號:

在不知道要分配的設備號的時候,可以使用動態分配的方式,函數如下:

1 int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

 

參數dev是僅用於輸出的參數,在成功完成調用后將保存已分配范圍的第一個編號;

參數baseminor是要使用的被請求的第一個次設備號,通常是0;

參數count標識分配設備號的個數;

參數name是和該編號范圍關聯的設備名稱;

始終使用動態分配設備編號:

對於新的驅動程序,強烈建議不要隨便選擇一個當前設備未使用的設備號作為主設備號,而應該使用動態分配機制獲取主設備號;驅動程序應該使用使用alloc_chrdev_region而不是register_chrdev_region函數;

動態分配的缺點:由於分配的主設備號不能始終保持一致,素以無法預先創建設備節點;對於驅動程序的一般做法是,為了加載一個使用動態主設備號的設備驅動程序,對insmod的調用可替換成一個簡單的腳本,該腳本在調用insmod之后讀取/proc/devices以獲得新分配的主設備號,然后創建對應的設備文件;

釋放設備編號:

在不使用設備編號的時候需要進行釋放,函數如下:

1 void unregister_chrdev_region(dev_t from, unsigned count)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM