驱动模型: platform总线,设备,驱动 3层架构框架
author: hjjdebug
date: 2026年 05月 07日 星期四 18:26:36 CST
descrip: 驱动模型: platform总线,设备,驱动 3层架构
1 概述:
platform总线不用我们写了,内核已经提供
设备模块是一个虚拟设备, 只做一件事:向内核平台总线 “插入” 一个设备。它本身不包含任何业务逻辑。
驱动是真正的 “驱动”.
当插上设备时,系统会扫描总线,找到名字匹配的驱动,然后执行probe函数,bind 成功。
操作: 把假设备当真设备
先加载驱动: sudo insmod virt_drv.ko
再加载设备: sudo insmod virt_dev.ko
其实,先安装谁都能匹配成功. 次序并不重要.
卸载,相反次序,先卸载设备,再卸载驱动. 其实卸载谁都不能配合工作了.次序不重要
sudo rmmod virt_dev
sudo rmmod virt_drv
2. 虚拟设备程序 virt_dev.c
内容非常简单, 定义一个平台设备, 只要给个名字就可以了.
然后,当insmod 时会执行初始化代码, 在初始化代码中在platform总线上去注册这个设备就可以了.
ret = platform_device_register(&my_virt_device);
当然,这个设备目前就是一个空设备.
卸载模块时,调用platform_device_unregister(&my_virt_device);
完整代码如下:
$ cat virt_dev.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
// 设备名称,驱动模块就是靠这个名字来匹配设备的
static struct platform_device my_virt_device = {
.name = "my_virt_device", // 关键:驱动要和这个名字一致
.id = -1,
};
static int __init virt_dev_init(void)
{
int ret;
ret = platform_device_register(&my_virt_device);
if (ret) {
pr_err("Failed to register platform device\n");
return ret;
}
pr_info("Virtual device registered: %s\n", my_virt_device.name);
return 0;
}
static void __exit virt_dev_exit(void)
{
platform_device_unregister(&my_virt_device);
pr_info("Virtual device unregistered\n");
}
module_init(virt_dev_init);
module_exit(virt_dev_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Virtual Hardware Device (No Logic)");
这里我们关注一下注册后,系统发生了什么变化.
- 总的设备树中多出了一个my_virt_device 设备. 对应了一个目录
/sys/devices/platform/my_virt_device
3 写一个驱动drv.c,
它在install 时,会调用平台驱动注册函数.
platform_driver_register(&my_virt_driver);
恰如虚拟设备的注册函数,那里注册的是设备,这里注册的是驱动
如果驱动的名称与设备注册的名称一致, 那就是匹配上了.
匹配上了,就叫bind 成功, 那个设备就是这个驱动,这个驱动就是那个设备的驱动.
从驱动角度看,匹配上了,就会调用platform_driver 的probe 函数. 进行后续工作…
框架就这么简单.
完整代码:
$ cat mydrv.c
#include <linux/module.h>
#include <linux/platform_device.h>
// --- 平台驱动的probe函数(设备匹配成功后调用)---
static int my_virt_probe(struct platform_device *pdev)
{
pr_info("Driver matched device: %s\n", pdev->name);
return 0;
}
// --- 平台驱动的remove函数(设备被移除时调用)---
static int my_virt_remove(struct platform_device *pdev)
{
pr_info("Driver removing device: %s\n", pdev->name);
return 0;
}
// --- 平台驱动结构体 ---
static struct platform_driver my_virt_driver = {
.probe = my_virt_probe,
.remove = my_virt_remove,
.driver = {
.name = "my_virt_device", // 关键:必须和设备的name一致
.owner = THIS_MODULE,
},
};
static int __init mydrv_init(void)
{
return platform_driver_register(&my_virt_driver);
}
static void __exit mydrv_exit(void)
{
platform_driver_unregister(&my_virt_driver);
}
module_init(mydrv_init);
module_exit(mydrv_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Driver for Virtual Hardware Device");
不过框架隐藏着一些底层的东西,还是要慢慢把它讲透.
当你insmod mydrv.ko 后,
会在 /sys/bus/platform/drivers/ 下生成 my_virt_device 目录(代码中定义的驱动名字)
代表平台总线驱动下又来了一位新成员
它里面有bind,unbind 文件,可以手工bind,unbind 设备
有一个module 连接,指向module 下模块实体.
module -> …/…/…/…/module/mydrv/
如果与设备匹配成功. 会创建一个指向设备的连接.如下:
my_virt_device -> …/…/…/…/devices/platform/my_virt_device/
同时在/sys/bus/platform/devices/ 下也会创建一个设备连接,指向设备实体. 这个目录下全是链接
/sys/bus/platform/devices$ ll my_virt_device
lrwxrwxrwx 1 root root 0 5月 7 17:33 my_virt_device -> …/…/…/devices/platform/my_virt_device/
现在你可以用下面2条命令结合dmesg 反复观察.probe 和.remove 函数的调用. 这就是驱动和设备bind,unbind的过程
echo “my_virt_device” |sudo tee unbind
echo “my_virt_device” |sudo tee bind
unbind 之后, 那些链接就被删除了. bind上之后,那些链接又回来了.
总得让驱动干点事情吧, 嗯, 那就后续完善probe 函数, 添加功能. 并配合虚拟设备,做点有意思的工作.
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)