Linux驱动 | cdev_init、cdev_alloc的区别
原创Linux驱动开发:cdev_init与cdev_alloc的区别
在Linux内核中,字符设备(char device)是一种常见的设备类型,它允许用户空间的应用程序通过标准文件操作与硬件设备进行交互。在驱动程序开发中,`cdev_init`和`cdev_alloc`是两个用于初始化字符设备结构体`struct cdev`的函数。这两个函数在功能和使用上有所区别,以下是它们之间的详细比较。
### 1. cdev_init
`cdev_init`函数用于初始化一个已经分配的`cdev`结构体。这个函数接收三个参数:一个指向`cdev`结构体的指针、一个指向设备号的指针和一个指向`struct module`结构体的指针。
c
int cdev_init(struct cdev *cdev, dev_t dev, struct module *owner);
- `cdev`: 指向要初始化的`cdev`结构体的指针。
- `dev`: 指向设备号的指针,用于设置`cdev`结构体中的`dev`成员。
- `owner`: 指向`struct module`结构体的指针,描述拥有该字符设备的模块。
`cdev_init`函数将`cdev`结构体中的成员初始化为默认值,并设置`dev`成员的值。如果`cdev`结构体已经初始化,则`cdev_init`会返回失误。
### 2. cdev_alloc
`cdev_alloc`函数用于动态分配一个`cdev`结构体,并初始化它。这个函数接收两个参数:一个指向`struct module`结构体的指针和一个指向设备号的指针。
c
struct cdev *cdev_alloc(struct module *owner, dev_t dev);
- `owner`: 指向`struct module`结构体的指针,描述拥有该字符设备的模块。
- `dev`: 指向设备号的指针,用于设置新分配的`cdev`结构体中的`dev`成员。
`cdev_alloc`函数会动态分配一个`cdev`结构体,并调用`cdev_init`来初始化它。如果分配未果,则返回`NULL`。
### 3. 区别
- **分配方案**:`cdev_init`需要一个已经分配的`cdev`结构体,而`cdev_alloc`会自动分配一个`cdev`结构体。
- **初始化时机**:`cdev_init`在`cdev`结构体已经分配后调用,而`cdev_alloc`在`cdev`结构体分配时调用。
- **返回值**:`cdev_init`如果`cdev`结构体已经初始化,则返回失误;而`cdev_alloc`如果分配未果,则返回`NULL`。
### 4. 使用场景
- **cdev_init**:适用于在驱动程序中,当`cdev`结构体已经通过其他方案(如`kmalloc`)分配后,需要对其进行初始化的情况。
- **cdev_alloc**:适用于在驱动程序中,当需要动态分配并初始化一个`cdev`结构体时。
### 5. 示例代码
以下是一个单纯的示例,展示了怎样使用`cdev_init`和`cdev_alloc`:
c
#include
#include
static struct cdev my_cdev;
static dev_t my_dev = MKDEV(0, 1);
static struct module *my_owner = THIS_MODULE;
static int __init my_cdev_init(void) {
if (cdev_init(&my_cdev, my_dev, my_owner)) {
printk(KERN_ERR "Failed to initialize cdev. ");
return -EFAULT;
}
cdev_add(&my_cdev, my_dev, 1);
return 0;
}
static void __exit my_cdev_exit(void) {
cdev_del(&my_cdev);
}
module_init(my_cdev_init);
module_exit(my_cdev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Example cdev initialization");
在这个示例中,我们使用`cdev_init`来初始化一个已经通过`kmalloc`分配的`cdev`结构体。
### 6. 总结
`cdev_init`和`cdev_alloc`是Linux内核中用于初始化字符设备结构体的两个函数。它们在功能和使用上有所不同,开发者应采取具体需求选择合适的函数。本文对这两个函数进行了详细的比较和说明,愿望对Linux驱动开发有所帮助。