想象一下, 你是一位城市交通规划师. 在没有统一交通规则之前, 每辆车都按自己的方式行驶——汽车走马路, 火车走铁轨, 飞机在天空, 但它们之间无法协同, 换乘困难, 调度混乱. 早期Linux内核的设备管理就类似这种状态: 每个驱动都是"特立独行"的孤岛, 没有统一的标准和管理机制
直到Linux 2.6内核, 设备驱动模型(Device Driver Model) 这座"智能交通管理中心"应运而生. 它通过统一的架构, 实现了:
Linux设备驱动模型的核心思想可以用三个词概括: 抽象、分层、统一. 它深受面向对象思想的影响, 但在C语言环境下巧妙实现

让我们把整个系统比作一个大型物流公司:
kobject是整个模型的最小原子, 它是面向对象思想在C语言中的具体实现
// include/linux/kobject.h 中的核心定义
struct kobject {
const char *name; // 对象名称
struct list_head entry; // 链表节点
struct kobject *parent; // 父对象(构建层次结构)
struct kset *kset; // 所属集合
struct kobj_type *ktype; // 对象类型描述符
struct kernfs_node *sd; // sysfs目录项
struct kref kref; // 引用计数
unsigned int state_initialized:1;// 初始化状态
// ...
};关键机制: 引用计数(kref)
// 生活比喻: 图书馆的书籍借阅系统
// 每本书被借出时, 借阅次数+1;归还时-1
// 当无人借阅时(计数为0), 书籍可被回收
struct kref {
refcount_t refcount; // 原子引用计数
};
// 增加引用
void kref_get(struct kref *kref) {
refcount_inc(&kref->refcount);
}
// 减少引用, 计数为0时调用release函数
void kref_put(struct kref *kref, void (*release)(struct kref *kref)) {
if (refcount_dec_and_test(&kref->refcount))
release(kref);
}
现实比喻: kset像是公司的部门(研发部、市场部), kobj_type像是员工职位描述(岗位职责、考核标准), kobject则是具体的员工个体
// include/linux/device.h 中的关键结构
// 设备结构: 代表一个物理或逻辑设备
struct device {
struct device *parent; // 父设备(构建设备树)
struct device_private *p; // 私有数据
struct kobject kobj; // 内嵌的kobject
const char *init_name; // 初始名称
struct device_type *type; // 设备类型
struct bus_type *bus; // 所属总线类型
struct device_driver *driver; // 绑定的驱动
void *platform_data; // 平台特定数据
void *driver_data; // 驱动私有数据
struct device_node *of_node; // 设备树节点
struct class *class; // 所属类别
// ... 电源管理、DMA、IO等众多字段
};
// 驱动结构: 知道如何操作某类设备
struct device_driver {
const char *name; // 驱动名称
struct bus_type *bus; // 所属总线
struct module *owner; // 模块所有者
const char *mod_name; // 模块名称
int (*probe)(struct device *dev); // 探测设备
int (*remove)(struct device *dev); // 移除设备
void (*shutdown)(struct device *dev); // 关闭设备
int (*suspend)(struct device *dev, pm_message_t state); // 挂起
int (*resume)(struct device *dev); // 恢复
// ... 更多操作函数
};总线是设备驱动模型中最关键的"媒人", 负责设备与驱动的匹配
struct bus_type {
const char *name; // 总线名称: pci, usb, platform等
int (*match)(struct device *dev, struct device_driver *drv); // 匹配函数
int (*uevent)(struct device *dev, struct kobj_uevent_env *env); // 用户事件
int (*probe)(struct device *dev); // 总线级探测
int (*remove)(struct device *dev); // 总线级移除
void (*shutdown)(struct device *dev); // 关闭
struct subsys_private *p; // 私有数据
struct lock_class_key lock_key;
};匹配流程的生活比喻:
设备驱动匹配就像一个相亲大会:
probe函数, 开启"恋爱关系"remove函数
sysfs是内核对象到用户空间的桥梁, 将内核数据结构映射为文件系统

# 查看系统所有PCI设备
ls -l /sys/bus/pci/devices/
# 查看特定设备的厂商和产品ID
cat /sys/bus/pci/devices/0000:00:1f.2/vendor
cat /sys/bus/pci/devices/0000:00:1f.2/device
# 查看设备绑定的驱动
ls -l /sys/bus/pci/devices/0000:00:1f.2/driver
# 查看所有输入设备
ls /sys/class/input/
# 查看网络设备状态
cat /sys/class/net/eth0/operstate让我们通过一个最简单的虚拟字符设备, 来理解整个设备驱动模型的工作流程
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#define DEVICE_NAME "vdev_example"
#define CLASS_NAME "vdevcls"
// 设备私有数据结构
struct vdev_data {
struct cdev cdev; // 字符设备结构
struct device *device; // 设备结构
char buffer[256]; // 设备数据缓冲区
int buffer_len; // 缓冲区长度
};
static int major_num = 0; // 主设备号(动态分配)
staticstruct class *vdev_class = NULL; // 设备类
staticstruct vdev_data *vdev_data = NULL; // 设备实例// 总线类型定义(模拟一个虚拟总线)
staticstruct bus_type vdev_bus_type = {
.name = "vdev_bus",
.match = vdev_bus_match,
.uevent = vdev_bus_uevent,
};
// 总线匹配函数
static int vdev_bus_match(struct device *dev, struct device_driver *drv)
{
printk(KERN_INFO "VDEV: 尝试匹配设备 %s 和驱动 %s\n",
dev_name(dev), drv->name);
// 简单的名称匹配逻辑
// 实际中会使用设备ID表进行匹配
return !strncmp(dev_name(dev), drv->name, strlen(drv->name));
}
// 设备结构定义
static void vdev_device_release(struct device *dev)
{
printk(KERN_INFO "VDEV: 设备 %s 被释放\n", dev_name(dev));
kfree(dev->parent); // 释放父设备
}
// 创建设备
static struct device *create_vdev_device(const char *name)
{
struct device *dev;
int ret;
// 分配设备结构
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return ERR_PTR(-ENOMEM);
// 初始化设备
dev->init_name = name;
dev->bus = &vdev_bus_type;
dev->release = vdev_device_release;
// 注册设备到总线
ret = device_register(dev);
if (ret < 0) {
printk(KERN_ERR "VDEV: 设备注册失败: %d\n", ret);
kfree(dev);
return ERR_PTR(ret);
}
printk(KERN_INFO "VDEV: 设备 %s 创建成功\n", name);
return dev;
}
// 驱动结构定义
static int vdev_driver_probe(struct device *dev)
{
struct vdev_data *data;
int ret;
dev_t devno;
printk(KERN_INFO "VDEV: 驱动探测设备 %s\n", dev_name(dev));
// 分配设备私有数据
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
// 创建设备号
if (major_num) {
devno = MKDEV(major_num, 0);
ret = register_chrdev_region(devno, 1, DEVICE_NAME);
} else {
ret = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME);
major_num = MAJOR(devno);
}
if (ret < 0) {
printk(KERN_ERR "VDEV: 无法分配设备号\n");
goto fail_alloc;
}
// 初始化字符设备
cdev_init(&data->cdev, &vdev_fops);
data->cdev.owner = THIS_MODULE;
ret = cdev_add(&data->cdev, devno, 1);
if (ret) {
printk(KERN_ERR "VDEV: 无法添加字符设备\n");
goto fail_cdev;
}
// 创建设备节点
data->device = device_create(vdev_class, NULL, devno, NULL, DEVICE_NAME);
if (IS_ERR(data->device)) {
ret = PTR_ERR(data->device);
printk(KERN_ERR "VDEV: 无法创建设备节点\n");
goto fail_device;
}
// 保存设备私有数据
dev_set_drvdata(dev, data);
vdev_data = data;
printk(KERN_INFO "VDEV: 设备 %s 初始化完成, 主设备号: %d\n",
DEVICE_NAME, major_num);
return 0;
fail_device:
cdev_del(&data->cdev);
fail_cdev:
unregister_chrdev_region(devno, 1);
fail_alloc:
kfree(data);
return ret;
}
static int vdev_driver_remove(struct device *dev)
{
struct vdev_data *data = dev_get_drvdata(dev);
dev_t devno = data->cdev.dev;
printk(KERN_INFO "VDEV: 移除设备 %s\n", dev_name(dev));
// 销毁设备节点
device_destroy(vdev_class, devno);
// 删除字符设备
cdev_del(&data->cdev);
// 释放设备号
unregister_chrdev_region(devno, 1);
// 释放设备数据
kfree(data);
vdev_data = NULL;
return 0;
}
// 驱动结构
staticstruct device_driver vdev_driver = {
.name = "vdev_example",
.bus = &vdev_bus_type,
.probe = vdev_driver_probe,
.remove = vdev_driver_remove,
};
// 文件操作结构
staticstruct file_operations vdev_fops = {
.owner = THIS_MODULE,
.read = vdev_read,
.write = vdev_write,
.open = vdev_open,
.release = vdev_release,
.llseek = noop_llseek,
};static int __init vdev_init(void)
{
int ret;
struct device *dev;
printk(KERN_INFO "VDEV: 初始化虚拟设备驱动\n");
// 注册总线
ret = bus_register(&vdev_bus_type);
if (ret) {
printk(KERN_ERR "VDEV: 总线注册失败: %d\n", ret);
return ret;
}
// 创建设备类
vdev_class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(vdev_class)) {
ret = PTR_ERR(vdev_class);
printk(KERN_ERR "VDEV: 无法创建设备类\n");
goto fail_class;
}
// 创建设备
dev = create_vdev_device("vdev_example");
if (IS_ERR(dev)) {
ret = PTR_ERR(dev);
goto fail_device;
}
// 注册驱动
ret = driver_register(&vdev_driver);
if (ret) {
printk(KERN_ERR "VDEV: 驱动注册失败: %d\n", ret);
goto fail_driver;
}
printk(KERN_INFO "VDEV: 驱动初始化成功\n");
return 0;
fail_driver:
device_unregister(dev);
fail_device:
class_destroy(vdev_class);
fail_class:
bus_unregister(&vdev_bus_type);
return ret;
}
static void __exit vdev_exit(void)
{
printk(KERN_INFO "VDEV: 卸载驱动\n");
// 注销驱动
driver_unregister(&vdev_driver);
// 销毁设备类
if (vdev_class)
class_destroy(vdev_class);
// 注销总线
bus_unregister(&vdev_bus_type);
printk(KERN_INFO "VDEV: 驱动卸载完成\n");
}
module_init(vdev_init);
module_exit(vdev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Device Model Expert");
MODULE_DESCRIPTION("Virtual Device Example for Linux Device Model");
MODULE_VERSION("1.0");# Makefile 示例
obj-m := vdev_example.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean测试步骤:
# 编译模块
make
# 加载模块
sudo insmod vdev_example.ko
# 查看内核日志
dmesg | tail -20
# 查看sysfs中的设备信息
ls -l /sys/bus/vdev_bus/
ls -l /sys/class/vdevcls/
ls -l /dev/vdev_example*
# 测试设备(需要实现read/write函数)
sudo cat /dev/vdev_example0
# 卸载模块
sudo rmmod vdev_example对于嵌入式系统, 设备树提供了硬件描述的标准方法
// 示例: 简单的设备树节点
vdev_example@0x10000000 {
compatible = "vendor,vdev-example-1.0";
reg = <0x10000000 0x1000>;
interrupts = <0 45 4>;
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
child@0 {
reg = <0>;
label = "child0";
};
};驱动中解析设备树:
static conststruct of_device_id vdev_of_match[] = {
{ .compatible = "vendor,vdev-example-1.0" },
{ .compatible = "vendor,vdev-example-2.0" },
{},
};
MODULE_DEVICE_TABLE(of, vdev_of_match);
static int vdev_probe_dt(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
const char *label;
u32 reg;
// 读取设备树属性
if (of_property_read_string(node, "label", &label) == 0)
printk(KERN_INFO "VDEV: 设备标签: %s\n", label);
if (of_property_read_u32(node, "reg", ®) == 0)
printk(KERN_INFO "VDEV: 寄存器地址: 0x%08x\n", reg);
// 遍历子节点
for_each_child_of_node(node, child) {
// 处理子设备
}
return 0;
}设备驱动模型集成了复杂的电源管理功能

电源管理操作示例:
// 电源管理操作集
static conststruct dev_pm_ops vdev_pm_ops = {
.suspend = vdev_suspend,
.resume = vdev_resume,
.freeze = vdev_freeze,
.thaw = vdev_thaw,
.poweroff = vdev_poweroff,
.restore = vdev_restore,
.runtime_suspend = vdev_runtime_suspend,
.runtime_resume = vdev_runtime_resume,
.runtime_idle = vdev_runtime_idle,
};
// 挂起设备
static int vdev_suspend(struct device *dev)
{
struct vdev_data *data = dev_get_drvdata(dev);
printk(KERN_INFO "VDEV: 挂起设备\n");
// 保存设备状态
data->saved_state = data->current_state;
// 关闭设备电源(如果支持)
if (data->power_control)
data->power_control(false);
return 0;
}
// 恢复设备
static int vdev_resume(struct device *dev)
{
struct vdev_data *data = dev_get_drvdata(dev);
printk(KERN_INFO "VDEV: 恢复设备\n");
// 恢复设备电源
if (data->power_control)
data->power_control(true);
// 恢复设备状态
data->current_state = data->saved_state;
return 0;
}lsmod | lsmod | grep vdev | |
modinfo | modinfo vdev_example | |
dmesg | dmesg -w | |
udevadm | udevadm info -a -p /sys/class/vdevcls/vdev_example0 | |
lspci | lspci -vvv | |
lsusb | lsusb -t | |
sysctl | sysctl -a | grep dev | |
cat /proc | cat /proc/devices | |
strace | strace cat /dev/vdev_example0 |
**动态调试(Dynamic Debug): **
# 启用特定文件的动态调试
echo "file vdev_example.c +p" > /sys/kernel/debug/dynamic_debug/control
# 启用特定函数的调试信息
echo "func vdev_probe +p" > /sys/kernel/debug/dynamic_debug/control
# 查看当前调试设置
cat /sys/kernel/debug/dynamic_debug/control | grep vdev**ftrace跟踪: **
# 启用函数跟踪
echo function > /sys/kernel/debug/tracing/current_tracer
echo vdev_* > /sys/kernel/debug/tracing/set_ftrace_filter
echo 1 > /sys/kernel/debug/tracing/tracing_on
# 执行操作
cat /dev/vdev_example0
# 查看跟踪结果
cat /sys/kernel/debug/tracing/trace**sysfs调试接口: **
// 在驱动中创建调试属性
static ssize_t debug_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct vdev_data *data = dev_get_drvdata(dev);
return sprintf(buf, "状态: %d\n缓冲区: %s\n",
data->state, data->buffer);
}
static ssize_t debug_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
// 解析用户输入, 执行调试操作
if (strncmp(buf, "reset", 5) == 0) {
// 重置设备
vdev_reset(dev);
}
return count;
}
static DEVICE_ATTR_RW(debug);
// 在probe函数中添加
device_create_file(dev, &dev_attr_debug);# 配置内核支持各种调试功能
make menuconfig
# 重要选项:
# Device Drivers -->
# [*] Driver Core verbose debug messages
# [*] Debug device deferred probing
# [*] Verbose sysfs creation/removal messages
# [*] Test driver loading with simulated firmware blobs
# [*] Test driver triggering events// 延迟初始化的例子
static int vdev_open(struct inode *inode, struct file *filp)
{
struct vdev_data *data = container_of(inode->i_cdev,
struct vdev_data, cdev);
// 首次打开时才完全初始化硬件
if (!data->initialized) {
int ret = vdev_hw_init(data);
if (ret)
return ret;
data->initialized = true;
}
filp->private_data = data;
return 0;
}static int vdev_probe(struct platform_device *pdev)
{
struct vdev_data *data;
struct resource *res;
int ret;
// 1. 按顺序分配资源, 失败时按相反顺序释放
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
// 2. 使用devm_系列函数自动管理资源
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
data->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(data->base))
return PTR_ERR(data->base);
// 3. 使用goto标签进行清晰的错误处理
ret = vdev_init_hardware(data);
if (ret < 0)
goto err_hw_init;
ret = vdev_register_chardev(data);
if (ret < 0)
goto err_chardev;
platform_set_drvdata(pdev, data);
return 0;
// 错误处理路径
err_chardev:
vdev_cleanup_hardware(data);
err_hw_init:
// devm_函数会自动清理, 无需手动释放
return ret;
}
| kobject | struct kobject | ||
| kset | struct kset | ||
| 设备 | struct device | ||
| 驱动 | struct device_driver | ||
| 总线 | struct bus_type | ||
| 类别 | struct class | ||
| 属性 | struct attribute | ||
| 设备树 | struct device_node |

device包含kobject, driver包含kobjectclass和bus负责创建和销毁设备节点Linux设备驱动模型是一个精心设计的复杂系统, 它通过分层抽象和统一管理, 解决了设备管理的根本问题. 从最简单的字符设备到最复杂的PCIe设备, 都遵循着相同的架构模式
掌握设备驱动模型不仅有助于编写更好的驱动程序, 更能深入理解Linux内核的设计哲学. 记住这个模型的核心理念: 一切皆对象, 一切皆文件, 一切皆层次