📖 推荐阅读:《Yocto项目实战教程:高效定制嵌入式Linux系统》
🎥 更多学习视频请关注 B 站:嵌入式Jerry
🧩 驱动注册的全景视角:从 module_init 到 /dev/xxx 的创建之路
在 Linux 驱动开发过程中,驱动的“注册”到底发生在哪?probe() 和 register 谁先谁后?设备节点 /dev/xxx 又是如何自动出现在系统中的?这些问题看似零散,实则密切关联,构成了驱动模型的关键骨架。本文将带你完整梳理内核驱动注册的全过程,帮助构建清晰的驱动执行链路。

✅ 一、Linux 内核驱动结构中常见的函数有哪些?
Linux 内核中的驱动程序通常包含以下几个核心函数与接口:
| 函数 / 宏名 | 作用描述 |
|---|---|
module_init() | 指定驱动模块加载时调用的初始化函数 |
module_exit() | 指定驱动卸载时调用的清理函数 |
xxx_driver.probe() | 设备匹配成功后被调用,用于资源申请与初始化 |
xxx_driver.remove() | 驱动卸载或设备移除时调用,用于资源释放 |
xxx_driver.register() | 驱动注册函数,注册到对应总线 |
register_chrdev() / cdev_add() | 注册字符设备,用于 /dev 节点创建 |
class_create() / device_create() | 创建 /dev 节点和 sysfs 接口 |
✅ 二、probe() 和 register() 的调用顺序是怎样的?
这是很多人易混淆的问题,其实:
register在前,probe在后。
解释如下:
register_driver()系列函数(如platform_driver_register()) 会将驱动挂接到内核的设备模型中。- 注册成功后,内核会遍历系统中的设备(如 platform_device),判断是否与该驱动匹配(通过 name、of_match_table、id_table 等方式)。
- 一旦匹配成功,就会调用
probe()函数,开始驱动与设备的绑定和初始化。
✅ 三、probe() 函数中是否包含 class_create() 等函数?
视情况而定。
- 如果你是字符设备驱动开发者,你通常会在
probe()函数中调用如下函数:
my_class = class_create(THIS_MODULE, "mydev");
device_create(my_class, NULL, devt, NULL, "mydev%d", minor);
- 这两个函数用于向用户空间导出设备节点,最终会在
/dev中生成你期望的设备文件,如/dev/mydev0。
🔍 补充说明:
class_create()会在/sys/class/下生成一个类;device_create()会创建/dev/xxx和/sys/class/xxx/下的节点。
✅ 四、驱动注册的调用入口究竟在哪里?
驱动的注册函数通常会写在 module_init() 宏指向的函数中,例如:
static int __init my_driver_init(void)
{
return platform_driver_register(&my_driver);
}
module_init(my_driver_init);
这个初始化函数会在模块被加载时执行。
✅ 五、module_init() 和 module_exit() 的作用与执行时机?
| 宏定义 | 描述 |
|---|---|
module_init(func) | 指定模块加载时执行的函数(比如注册驱动) |
module_exit(func) | 指定模块卸载时执行的函数(比如释放资源) |
这两个宏会在模块加载与卸载的过程中自动执行,实际是注册到了特殊的段中:
__initcall用于 module_init。__exitcall用于 module_exit。
✅ 六、字符设备节点 /dev/xxx 是如何创建的?
这是许多驱动开发新手关心的问题,下面以字符设备为例讲解整个流程:
1. 分配设备号(或使用静态设备号)
alloc_chrdev_region(&devt, 0, 1, "mydev");
2. 初始化并添加 cdev 结构
cdev_init(&my_cdev, &fops);
cdev_add(&my_cdev, devt, 1);
3. 创建 class 和 device,用于 udev 创建设备节点
my_class = class_create(THIS_MODULE, "mydev");
device_create(my_class, NULL, devt, NULL, "mydev%d", 0);
4. 用户空间中的 udev 会根据 sysfs 下的信息自动在 /dev/ 中创建对应节点。
✅ 七、一个完整的示意流程图
module_init() ─────┬────────┐
▼ ▼
register_xxx_driver() │
│
匹配到 device -> probe()
├── register_chrdev() / cdev_add()
├── class_create()
└── device_create() → 生成 /dev/xxx
🔚 总结归纳
| 问题点 | 简明回答 |
|---|---|
| 驱动常见函数 | module_init, probe, register, class_create, device_create |
| probe 和 register 顺序 | register 先,probe 后 |
| class_create 调用位置 | 通常在 probe 函数中 |
| 注册函数调用位置 | 写在 module_init 指定的初始化函数中 |
| module_init 作用 | 模块加载时调用注册代码 |
| /dev/xxx 创建机制 | class_create + device_create + udev |
🎯 结语:建立驱动模型全局视角
驱动开发不只是调试 probe(),而是理解从驱动注册、设备匹配、字符设备注册到用户空间节点自动创建的一整套机制。掌握这一流程后,你才能真正从“写驱动”跨越到“设计驱动”的层次。
📌 如果你正准备开发一个字符设备或平台设备驱动,不妨从上述结构入手,搭建你自己的驱动框架。
📖 推荐阅读:《Yocto项目实战教程:高效定制嵌入式Linux系统》
🎥 更多学习视频请关注 B 站:嵌入式Jerry
785

被折叠的 条评论
为什么被折叠?



