学无止境-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号