Linux设备驱动模型深度解剖: 从设计哲学到实战演练

Linux设备驱动模型深度解剖: 从设计哲学到实战演练

引言: 为什么需要设备驱动模型?

想象一下, 你是一位城市交通规划师. 在没有统一交通规则之前, 每辆车都按自己的方式行驶------汽车走马路, 火车走铁轨, 飞机在天空, 但它们之间无法协同, 换乘困难, 调度混乱. 早期Linux内核的设备管理就类似这种状态: 每个驱动都是"特立独行"的孤岛, 没有统一的标准和管理机制

直到Linux 2.6内核, 设备驱动模型(Device Driver Model) 这座"智能交通管理中心"应运而生. 它通过统一的架构, 实现了:

  • 设备的自动发现和配置(就像交通摄像头自动识别车辆)
  • 驱动与设备的智能匹配(像为每辆车分配最合适的司机)
  • 电源管理的统一协调(类似全城红绿灯的智能调度)
  • 用户空间的标准化接口(如同统一的交通信息服务APP)

一、设计思想: 分层抽象与面向对象

1.1 设计哲学

Linux设备驱动模型的核心思想可以用三个词概括: 抽象、分层、统一. 它深受面向对象思想的影响, 但在C语言环境下巧妙实现
用户空间
sysfs虚拟文件系统
内核对象kobject
设备核心层
驱动核心层
总线类型子系统
具体设备实例
具体驱动实现

1.2 生活化比喻

让我们把整个系统比作一个大型物流公司:

  • 设备(Device) = 货物(需要运输的物品)
  • 驱动(Driver) = 运输车辆和司机(知道如何运输特定货物)
  • 总线(Bus) = 运输路线(公路、铁路、空运)
  • 类别(Class) = 货物分类(易碎品、危险品、普通货物)
  • kobject = 物流标签(包含所有元数据: ID、状态、位置等)

二、核心概念深度剖析

2.1 kobject: 万物皆对象的基石

kobject是整个模型的最小原子, 它是面向对象思想在C语言中的具体实现

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)

c 复制代码
// 生活比喻: 图书馆的书籍借阅系统
// 每本书被借出时, 借阅次数+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);
}

2.2 kset和kobj_type: 对象的分组与行为

类型描述
所属集合
包含对象
1 1 1 1 0..1 many kobject
+const char* name
+struct kobject* parent
+struct kset* kset
+struct kobj_type* ktype
+struct kref kref
+kobject_init()
+kobject_add()
+kobject_put()
kset
+struct list_head list
+struct kobject kobj
+struct kset_uevent_ops* uevent_ops
+kset_register()
+kset_create_and_add()
kobj_type
+struct sysfs_ops* sysfs_ops
+struct attribute** default_attrs
+void (release)(struct kobject)
+const char* (name)(struct kobject)

现实比喻 : kset像是公司的部门(研发部、市场部), kobj_type像是员工职位描述(岗位职责、考核标准), kobject则是具体的员工个体

2.3 device和device_driver: 主角登场

c 复制代码
// 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);  // 恢复
    // ... 更多操作函数
};

2.4 bus_type: 匹配的媒人

总线是设备驱动模型中最关键的"媒人", 负责设备与驱动的匹配

c 复制代码
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;
};

匹配流程的生活比喻 :

设备驱动匹配就像一个相亲大会:

  1. 设备带着自己的"简历"(device结构, 包含ID、能力等)
  2. 驱动带着自己的"择偶标准"(device_driver结构, 包含支持的设备ID表)
  3. 总线作为"媒人"(bus_type), 按照规则(match函数)进行匹配
  4. 匹配成功后, 调用驱动的probe函数, 开启"恋爱关系"
  5. 分手时(设备移除或驱动卸载), 调用remove函数

sysfs 驱动 设备 总线核心 内核 用户空间 sysfs 驱动 设备 总线核心 内核 用户空间 loop [对每个设备尝试匹配] insmod driver.ko 驱动注册 bus_add_driver() 遍历总线上所有设备 match(dev, drv) 调用驱动的probe() 初始化设备 创建设备属性文件 返回成功 注册完成 返回成功

三、sysfs: 用户空间的窗口

sysfs是内核对象到用户空间的桥梁, 将内核数据结构映射为文件系统
sys
bus/
devices/
class/
dev/
pci/
usb/
platform/
devices/
0000:00:1f.2/
vendor
device
driver/
net/
input/
block/
eth0/
address
mtu
operstate
rtc/
tty/
sound/
block/
char/

3.1 sysfs操作示例

bash 复制代码
# 查看系统所有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

四、完整实例: 虚拟字符设备驱动

让我们通过一个最简单的虚拟字符设备, 来理解整个设备驱动模型的工作流程

4.1 设备结构定义

c 复制代码
#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;              // 主设备号(动态分配)
static struct class *vdev_class = NULL; // 设备类
static struct vdev_data *vdev_data = NULL; // 设备实例

4.2 总线、设备、驱动的完整实现

c 复制代码
// 总线类型定义(模拟一个虚拟总线)
static struct 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;
}

// 驱动结构
static struct device_driver vdev_driver = {
    .name = "vdev_example",
    .bus = &vdev_bus_type,
    .probe = vdev_driver_probe,
    .remove = vdev_driver_remove,
};

// 文件操作结构
static struct file_operations vdev_fops = {
    .owner = THIS_MODULE,
    .read = vdev_read,
    .write = vdev_write,
    .open = vdev_open,
    .release = vdev_release,
    .llseek = noop_llseek,
};

4.3 模块初始化和退出

c 复制代码
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");

4.4 编译和测试

makefile 复制代码
# 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

测试步骤:

bash 复制代码
# 编译模块
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

五、设备树(Device Tree): 硬件描述的革新

对于嵌入式系统, 设备树提供了硬件描述的标准方法

dts 复制代码
// 示例: 简单的设备树节点
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";
    };
};

驱动中解析设备树:

c 复制代码
static const struct 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", &reg) == 0)
        printk(KERN_INFO "VDEV: 寄存器地址: 0x%08x\n", reg);
    
    // 遍历子节点
    for_each_child_of_node(node, child) {
        // 处理子设备
    }
    
    return 0;
}

六、电源管理: 智能节能机制

设备驱动模型集成了复杂的电源管理功能
电源关闭
电源打开
系统挂起
设备激活
设备空闲
用户访问
电源关闭
电源关闭
电源恢复
Unknown
Off
On
Suspended
Active

电源管理操作示例:

c 复制代码
// 电源管理操作集
static const struct 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;
}

七、调试和诊断工具

7.1 常用命令工具

工具命令 功能描述 示例用法
lsmod 查看已加载模块 `lsmod
modinfo 查看模块信息 modinfo vdev_example
dmesg 查看内核日志 dmesg -w (实时查看)
udevadm 管理设备事件 udevadm info -a -p /sys/class/vdevcls/vdev_example0
lspci 查看PCI设备 lspci -vvv (详细信息)
lsusb 查看USB设备 lsusb -t (树状显示)
sysctl 查看/修改内核参数 `sysctl -a
cat /proc 查看proc文件系统 cat /proc/devices (查看设备号)
strace 跟踪系统调用 strace cat /dev/vdev_example0

7.2 高级调试技巧

**动态调试(Dynamic Debug): **

bash 复制代码
# 启用特定文件的动态调试
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跟踪: **

bash 复制代码
# 启用函数跟踪
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调试接口: **

c 复制代码
// 在驱动中创建调试属性
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);

7.3 内核调试配置

bash 复制代码
# 配置内核支持各种调试功能
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

八、性能优化与最佳实践

8.1 性能优化技巧

  1. 延迟初始化: 只有在真正需要时才初始化设备
  2. 电源状态管理: 合理使用runtime PM
  3. 中断优化: 使用线程化中断减少延迟
  4. DMA缓存优化: 正确使用DMA缓冲区
  5. 资源复用: 避免重复分配和释放
c 复制代码
// 延迟初始化的例子
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;
}

8.2 错误处理最佳实践

c 复制代码
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;
}

九、总结与核心概念梳理

9.1 设备驱动模型核心架构总结

内核空间
用户空间
硬件抽象
具体子系统
设备管理
设备模型核心
应用程序
系统工具
配置文件
sysfs文件系统
kobject
kset
kobj_type
struct device
struct device_driver
struct bus_type
struct class
struct subsystem
PCI子系统
USB子系统
Platform总线
ACPI支持
设备树支持
字符设备
块设备
网络设备
杂项设备

9.2 核心概念对照表

概念 数据结构 作用 生活比喻
kobject struct kobject 所有对象的基类, 提供引用计数、sysfs接口 物流标签(包含ID、状态、位置)
kset struct kset kobject的集合, 提供分组管理 物流仓库(存放同类货物)
设备 struct device 代表一个物理或逻辑设备 货物(需要运输的物品)
驱动 struct device_driver 知道如何操作某类设备 运输车辆和司机
总线 struct bus_type 设备和驱动的匹配中介 运输路线和匹配系统
类别 struct class 按功能对设备分类 货物分类(易碎、危险等)
属性 struct attribute sysfs中的可读写属性 货物标签上的详细信息
设备树 struct device_node 硬件描述信息 货物的出厂说明书

9.3 设备生命周期管理

用户空间 内核 总线 驱动 设备 硬件 用户空间 内核 总线 驱动 设备 硬件 1. 设备发现阶段 2. 驱动匹配阶段 3. 设备使用阶段 4. 设备移除阶段 硬件插入/系统启动 创建设备对象 注册到总线 触发uevent 发送uevent到用户空间 加载驱动模块 注册驱动 注册到总线 遍历设备进行匹配 调用probe函数 初始化设备 创建设备节点 设备可用 用户操作设备 调用驱动操作函数 控制硬件 硬件移除/系统关闭 调用remove函数 清理设备资源 删除设备节点 发送移除事件 注销驱动

9.4 关键设计模式总结

  1. 组合模式 : device包含kobject, driver包含kobject
  2. 观察者模式: uevent机制通知用户空间设备状态变化
  3. 策略模式: 不同的总线类型实现不同的匹配策略
  4. 工厂模式 : classbus负责创建和销毁设备节点
  5. 访问者模式: sysfs属性文件提供统一的访问接口

结语

Linux设备驱动模型是一个精心设计的复杂系统, 它通过分层抽象和统一管理, 解决了设备管理的根本问题. 从最简单的字符设备到最复杂的PCIe设备, 都遵循着相同的架构模式

掌握设备驱动模型不仅有助于编写更好的驱动程序, 更能深入理解Linux内核的设计哲学. 记住这个模型的核心理念: 一切皆对象, 一切皆文件, 一切皆层次

相关推荐
明洞日记2 小时前
【CUDA手册002】CUDA 基础执行模型:写出第一个正确的 Kernel
c++·图像处理·算法·ai·图形渲染·gpu·cuda
半夏知半秋2 小时前
kcp学习-通用的kcp lua绑定
服务器·开发语言·笔记·后端·学习
Ydwlcloud2 小时前
AWS 2026折扣活动深度解析:寻找最大优惠的智慧路径
大数据·服务器·人工智能·云计算·aws
2401_832298102 小时前
芯片级机密计算,天翼云CSV3筑牢数据“可用不可见”防线
大数据·网络·人工智能
tjjingpan2 小时前
HCIP-Datacom Core Technology V1.0_13 园区网典型技术应用概述
网络
企业对冲系统官2 小时前
基差风险管理系统集成说明与接口规范
大数据·运维·python·算法·区块链·github
松涛和鸣2 小时前
DAY55 Getting Started with ARM and IMX6ULL
linux·服务器·网络·arm开发·数据库·html
程序员-King.2 小时前
day134—快慢指针—环形链表(LeetCode-141)
算法·leetcode·链表·快慢指针
Swift社区2 小时前
LeetCode 376 摆动序列
算法·leetcode·职场和发展