學無止境-Linux-申請設備號注意事項
備注:學習記錄所用,若有高手不吝賜教,萬分感謝!
申請設備號過程現在基本都是如下:
#define N_DEVS_MINOR 32
if(major) {
devno = MKDEV(major, 0);
ret = register_chrdev_region(devno, N_DEVS_MINOR, DEV_NAME);
}
else{
ret = alloc_chrdev_region(&devno, 0, N_DEVS_MINOR, DEV_NAME);
major = MAJOR(devno);
minor = MINOR(devno);
}
if (ret)
goto fail_chrdev;
網上對于設備號的解釋也基本如下:設備號分為主設備號和次設備號。其中主設備號是用來區分不同類別的設備,而次設備號用來區分一類設備中的不同個體。
需要注意的是:以上的申請過程摻雜有次設備號在里面,所以容易忽視“同類別設備”和“個體設備”的區分;上面代碼申請的設備號實際上主要是“用來區分不同類別的設備”。
而想要為同一類別設備的不同個體申請設備號,則應該按以下流程:
1、按照上面的代碼申請一個設備號(也可以直接當作:同類設備的第一個個體的設備號)。
個人理解這一步主要是用來申請“主設備號”,也就是用來區分設備的類別,此處的DEV_NAME也應該是設備類別名(如:spi),而不是個體設備名(如:spi0、spi1)。
申請完成后應該將主設備號:major = MAJOR(devno);記錄下來,以供為其他不同個體申請設備號時使用。
2、為其他不同個體申請設備號:
/*為一類設備申請設備號“空間”,
假如這一類設備一共可以有32個不同的個體*/
#define N_DEVS_MINOR 32
static DECLARE_BITMAP(minors, N_DEVS_MINOR);
/*從“空間”中為個體申請一個子設備號*/
minor = find_first_zero_bit(minors, N_DEVS_MINOR);
/*這里的主設備號,就是從第一步申請的設備號中獲取出來的*/
devno = MKDEV(major, minor);
再做其他過程,如:
err = cdev_add(&cdev, devno, N_DEVS_MINOR);
dev = device_create(class, NULL, devno, NULL, name);
/*設備注冊完成之后,將已經申請的個體子設備號“鎖住”,
申請主設備號(也是第一個設備的主次設備號)時,是否要鎖子設備號待驗證*/
set_bit(minor, minors);
所以可以這么寫:
#define N_DEVS_MINOR 32
static DECLARE_BITMAP(minors, N_DEVS_MINOR);
/*也可以直接給定一個值,
先“cat /proc/devices”查看當前有哪些已經被申請的設備號,
避免沖突*/
int major = 0;
void func_register_devt()
{
if(major) {
devno = MKDEV(major, 0);
ret = register_chrdev_region(devno, N_DEVS_MINOR, DEV_NAME);
}
else{
ret = alloc_chrdev_region(&devno, 0, N_DEVS_MINOR, DEV_NAME);
major = MAJOR(devno);
//minor = MINOR(devno); 個人認為沒必要記錄
}
if (ret)
goto fail_chrdev;
}
void func_register_spi_device(char *name, int id)
{
int minor = 0;
dev_t devno = 0;
minor = find_first_zero_bit(minors, N_DEVS_MINOR);
devno = MKDEV(major, minor);
sprintf(name, "spi-%d", id);
……
cdev_add(&cdev, devno, N_DEVS_MINOR);
dev = device_create(class, NULL, devno, NULL, name);
……
set_bit(minor, minors);
……
}
設備號申請函數調用一次即可。
這只是一種代碼格式,只要保證申請主設備號的過程只執行一次就行。
注:設備號充足的情況下,為每個個體都單獨申請一個主設備號也沒事。

浙公網安備 33010602011771號