一個字符設備或者塊設備都有一個主設備號和次設備號。主設備號和次設備號統稱為設
備號。主設備號用來表示一個特定的驅動程序。次設備號用來表示使用該驅動程序的各
設備。例如一個嵌入式系統,有兩個LED指示燈,LED燈需要獨立的打開或者關閉。那么
,可以寫一個LED燈的字符設備驅動程序,可以將其主設備號注冊成5號設備,次設備號
分別為1和2。這里,次設備號就分別表示兩個LED燈。
1.主設備號和次設備號的表示
在Linux內核中,dev_t類型用來表示設備號。在Linux 2.6.29.4中,dev_t定義為一個
無符號長整型變量,如下:typedef u_long dev_t;
u_long在32位機中是4個字節,在64位機中是8字節。以32位機為例,其中高12表示主設備號,低20為表示次設備號,如圖6.1所示。
2.主設備號和次設備號的獲取
為了寫出可移植的驅動程序,不能假定主設備號和次設備號的位數。不同的機型中,主
設備號和次設備號的位數可能是不同的。應該使用MAJOR宏得到主設備號,使用MINOR宏來得到次設備號。下面是兩個宏的定義:
#define MINORBITS? ?20? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? /*次設備號位數*/
#define MINORMASK? ?((1U << MINORBITS) - 1)? ?? ?? ?? ? /*次設備號掩碼*/
#define MAJOR(dev)??((unsigned int) ((dev) >> MINORBITS))
/*dev右移20位得到主設備號*/?
#define MINOR(dev)((unsigned int) ((dev) & MINORMASK))
? ?/*與次設備掩碼與,得到次設備號*/
MAJOR宏將dev_t向右移動20位,得到主設備號;MINOR宏將dev_t的高12位清零,得到次
設備號。相反,可以將主設備號和次設備號轉換為設備號類型(dev_t),使用宏
MKDEV可以完成這個功能。#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))??
MKDEV宏將主設備號(ma)左移20位,然后與次設備號(mi)相與,得到設備號。
3.靜態分配設備號
靜態分配設備號,就是驅動程序開發者,靜態地指定一個設備號。對于一部分常用的設
備,內核開發者已經為其分配了設備號。這些設備號可以在內核源碼documentation/
devices.txt文件中找到。如果只有開發者自己使用這些設備驅動程序,那么其可以選
擇一個尚未使用的設備號。在不添加新硬件的時候,這種方式不會產生設備號沖突。但
是當添加新硬件時,則很可能造成設備號沖突,影響設備的使用。
4.動態分配設備號
由于靜態分配設備號存在沖突的問題,所以內核社區建議開發者使用動態分配設備號的
方法。動態分配設備號的函數是alloc_chrdev_region()。
5.查看設備號
當靜態分配設備號時,需要查看系統中已經存在的設備號,從而決定使用哪個新設備號
。可以讀取/proc/devices文件獲得設備的設備號。/proc/devices文件包含字符設備和
塊設備的設備號,如下所示。[root@tom /]# cat /proc/devices /*cat命令查看
/proc/devices文件的內容*/??Character devices:? ?? ?? ?? ?? ?? ?/*字符設備*/
1 mem? ? 4 /dev/vc/0? ? 7 vcs? ? 13 input? ? 14 sound? ? 21 sg??Block
devices:??/*塊設備*/? ? 1 ramdisk? ? 2 fd? ? 8 sd? ? 253??device-mapper? ? 254 mdp??
3. 6.1.3 申請和釋放設備號
內核維護著一個特殊的數據結構,用來存放設備號與設備的關系。在安裝設備時,應該
給設備申請一個設備號,使系統可以明確設備對應的設備號。設備驅動程序中的很多功
能,是通過設備號來操作設備的。下面,首先對申請設備號進行簡述。
1.申請設備號
在構建字符設備之前,首先要向系統申請一個或者多個設備號。完成該工作的函數是
register_chrdev_region(),該函數在<fs/char_dev.c>中定義:
int register_chrdev_region(dev_t from, unsigned count, const char *name);
其中,from是要分配的設備號范圍的起始值。一般只提供from的主設備號,from的次設
備號通常被設置成0。count是需要申請的連續設備號的個數。最后name是和該范圍編號
關聯的設備名稱,該名稱不能超過64字節。
和大多數內核函數一樣,register_chrdev_region()函數成功時返回0。錯誤時,返回
一個負的錯誤碼,并且不能為字符設備分配設備號。下面是一個例子代碼,其申請了
CS5535_GPIO_COUNT個設備號。retval = register_chrdev_region(dev_id,
CS5535_GPIO_COUNT,NAME);
在Linux中有非常多的字符設備,在人為的為字符設備分配設備號時,很可能發生沖突
。Linux內核開發者一直在努力將設備號變為動態的。可以使用
alloc_chrdev_region()函數達到這個目的。
int alloc_chrdev_region(dev_t *dev, unsigned baseminor,unsigned count, const char *name)
在上面的函數中,dev作為輸出參數,在函數成功返回后將保存已經分配的設備號。函
數有可能申請一段連續的設備號,這是dev返回第一個設備號。baseminor表示要申請的
第一個次設備號,其通常設為0。count和name與register_chrdev_region()函數的對應
參數一樣。count表示要申請的連續次設備號個數,name表示設備的名字。下面是一個例
子代碼,其申請了CS5535_GPIO_COUNT個次設備號。retval =
alloc_chrdev_region(&dev_id, 0, CS5535_GPIO_COUNT, NAME);
2.釋放設備號
使用上面兩種方式申請的設備號,都應該在不使用設備時,釋放設備號。設備號的釋放
統一使用下面的函數:void unregister_chrdev_region(dev_t from, unsignedcount);
在上面這個函數中,from表示要釋放的設備號,count表示從from開始要釋放的次設備號
備號。主設備號用來表示一個特定的驅動程序。次設備號用來表示使用該驅動程序的各
設備。例如一個嵌入式系統,有兩個LED指示燈,LED燈需要獨立的打開或者關閉。那么
,可以寫一個LED燈的字符設備驅動程序,可以將其主設備號注冊成5號設備,次設備號
分別為1和2。這里,次設備號就分別表示兩個LED燈。
1.主設備號和次設備號的表示
在Linux內核中,dev_t類型用來表示設備號。在Linux 2.6.29.4中,dev_t定義為一個
無符號長整型變量,如下:typedef u_long dev_t;
u_long在32位機中是4個字節,在64位機中是8字節。以32位機為例,其中高12表示主設備號,低20為表示次設備號,如圖6.1所示。
2.主設備號和次設備號的獲取
為了寫出可移植的驅動程序,不能假定主設備號和次設備號的位數。不同的機型中,主
設備號和次設備號的位數可能是不同的。應該使用MAJOR宏得到主設備號,使用MINOR宏來得到次設備號。下面是兩個宏的定義:
#define MINORBITS? ?20? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? /*次設備號位數*/
#define MINORMASK? ?((1U << MINORBITS) - 1)? ?? ?? ?? ? /*次設備號掩碼*/
#define MAJOR(dev)??((unsigned int) ((dev) >> MINORBITS))
/*dev右移20位得到主設備號*/?
#define MINOR(dev)((unsigned int) ((dev) & MINORMASK))
? ?/*與次設備掩碼與,得到次設備號*/
MAJOR宏將dev_t向右移動20位,得到主設備號;MINOR宏將dev_t的高12位清零,得到次
設備號。相反,可以將主設備號和次設備號轉換為設備號類型(dev_t),使用宏
MKDEV可以完成這個功能。#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))??
MKDEV宏將主設備號(ma)左移20位,然后與次設備號(mi)相與,得到設備號。
3.靜態分配設備號
靜態分配設備號,就是驅動程序開發者,靜態地指定一個設備號。對于一部分常用的設
備,內核開發者已經為其分配了設備號。這些設備號可以在內核源碼documentation/
devices.txt文件中找到。如果只有開發者自己使用這些設備驅動程序,那么其可以選
擇一個尚未使用的設備號。在不添加新硬件的時候,這種方式不會產生設備號沖突。但
是當添加新硬件時,則很可能造成設備號沖突,影響設備的使用。
4.動態分配設備號
由于靜態分配設備號存在沖突的問題,所以內核社區建議開發者使用動態分配設備號的
方法。動態分配設備號的函數是alloc_chrdev_region()。
5.查看設備號
當靜態分配設備號時,需要查看系統中已經存在的設備號,從而決定使用哪個新設備號
。可以讀取/proc/devices文件獲得設備的設備號。/proc/devices文件包含字符設備和
塊設備的設備號,如下所示。[root@tom /]# cat /proc/devices /*cat命令查看
/proc/devices文件的內容*/??Character devices:? ?? ?? ?? ?? ?? ?/*字符設備*/
1 mem? ? 4 /dev/vc/0? ? 7 vcs? ? 13 input? ? 14 sound? ? 21 sg??Block
devices:??/*塊設備*/? ? 1 ramdisk? ? 2 fd? ? 8 sd? ? 253??device-mapper? ? 254 mdp??
3. 6.1.3 申請和釋放設備號
內核維護著一個特殊的數據結構,用來存放設備號與設備的關系。在安裝設備時,應該
給設備申請一個設備號,使系統可以明確設備對應的設備號。設備驅動程序中的很多功
能,是通過設備號來操作設備的。下面,首先對申請設備號進行簡述。
1.申請設備號
在構建字符設備之前,首先要向系統申請一個或者多個設備號。完成該工作的函數是
register_chrdev_region(),該函數在<fs/char_dev.c>中定義:
int register_chrdev_region(dev_t from, unsigned count, const char *name);
其中,from是要分配的設備號范圍的起始值。一般只提供from的主設備號,from的次設
備號通常被設置成0。count是需要申請的連續設備號的個數。最后name是和該范圍編號
關聯的設備名稱,該名稱不能超過64字節。
和大多數內核函數一樣,register_chrdev_region()函數成功時返回0。錯誤時,返回
一個負的錯誤碼,并且不能為字符設備分配設備號。下面是一個例子代碼,其申請了
CS5535_GPIO_COUNT個設備號。retval = register_chrdev_region(dev_id,
CS5535_GPIO_COUNT,NAME);
在Linux中有非常多的字符設備,在人為的為字符設備分配設備號時,很可能發生沖突
。Linux內核開發者一直在努力將設備號變為動態的。可以使用
alloc_chrdev_region()函數達到這個目的。
int alloc_chrdev_region(dev_t *dev, unsigned baseminor,unsigned count, const char *name)
在上面的函數中,dev作為輸出參數,在函數成功返回后將保存已經分配的設備號。函
數有可能申請一段連續的設備號,這是dev返回第一個設備號。baseminor表示要申請的
第一個次設備號,其通常設為0。count和name與register_chrdev_region()函數的對應
參數一樣。count表示要申請的連續次設備號個數,name表示設備的名字。下面是一個例
子代碼,其申請了CS5535_GPIO_COUNT個次設備號。retval =
alloc_chrdev_region(&dev_id, 0, CS5535_GPIO_COUNT, NAME);
2.釋放設備號
使用上面兩種方式申請的設備號,都應該在不使用設備時,釋放設備號。設備號的釋放
統一使用下面的函數:void unregister_chrdev_region(dev_t from, unsignedcount);
在上面這個函數中,from表示要釋放的設備號,count表示從from開始要釋放的次設備號
個數。通常,在模塊的卸載函數中調用unregister_chrdev_region()函數。