当前位置: 首页 > news >正文

Linux设备模型深度解析

深入分析 Linux 设备模型

一、工作原理

Linux 设备模型 (LDM) 的核心是 统一设备管理框架,通过以下机制实现:

  1. 抽象层次结构
    • 总线 (Bus) → 设备 (Device) → 驱动 (Driver) → 类 (Class)
    • 使用 kobject 实现面向对象模型(继承、多态)
  2. 自动匹配机制
    • 总线负责检测设备并与驱动匹配(match 函数)
  3. 统一用户接口
    • 通过 sysfs (/sys) 暴露设备信息
  4. 生命周期管理
    • 引用计数 (kref) 自动管理对象生存期
  5. 热插拔支持
    • 通过 uevent 机制通知用户空间(如 udev)
二、实现机制与代码框架

核心组件关系图

kobject → kset → subsystem↑device → device_driver↑       ↑bus_type

1. 核心数据结构

// <linux/kobject.h>
struct kobject {const char *name;                 // sysfs 目录名struct list_head entry;           // kset 链表节点struct kobject *parent;           // 父对象(形成层次结构)struct kset *kset;                // 所属集合struct kobj_type *ktype;          // 对象类型(操作函数)struct kernfs_node *sd;           // sysfs 节点struct kref kref;                 // 引用计数
};// <linux/device.h>
struct device {struct kobject kobj;              // 继承 kobjectstruct device *parent;            // 父设备struct device_driver *driver;     // 绑定的驱动struct bus_type *bus;             // 所属总线void *platform_data;              // 设备私有数据// ...
};struct device_driver {const char *name;                 // 驱动名称struct bus_type *bus;             // 所属总线int (*probe)(struct device *dev); // 设备探测函数int (*remove)(struct device *dev);// 设备移除函数struct driver_private *p;         // 私有数据
};struct bus_type {const char *name;                 // 总线名(如 "platform")int (*match)(struct device *dev, struct device_driver *drv); // 匹配函数struct kset devices;              // 总线上所有设备struct kset drivers;              // 总线上所有驱动
};

2. 工作流程

  1. 总线注册bus_register() 创建 /sys/bus/xxx
  2. 设备注册device_register() → 添加到总线设备链表 → 触发匹配
  3. 驱动注册driver_register() → 遍历总线设备链表尝试匹配
  4. 匹配执行:调用总线的 match() 函数
  5. 绑定驱动:匹配成功则调用驱动的 probe()
  6. 移除路径:设备/驱动卸载时调用 remove() → 解绑

三、Linux设备模型核心目标

  1. 统一设备表示:抽象硬件设备为内核对象
  2. 动态电源管理:支持设备热插拔与电源状态转换
  3. 用户空间接口:通过sysfs暴露设备拓扑与属性
  4. 设备驱动绑定:自动匹配设备与驱动

四、核心架构与组件关系

KObject
SysFS接口
引用计数
KSet集合
KType操作集
Device设备
Driver驱动
Bus总线

五、核心数据结构与关系

1. 关键结构体
结构体作用关键成员
struct kobject基础对象name, kref, parent, kset, ktype
struct ksetkobject容器list(对象链表), kobj(内嵌kobject)
struct ktype定义对象行为release(释放函数), sysfs_ops
struct device设备抽象parent, bus, driver, kobj
struct device_driver驱动抽象name, bus, probe, remove
struct bus_type总线抽象name, match, probe, remove
2. 对象关系图
kobject
+char *name
+struct kref kref
+struct kset *kset
+struct kobj_type *ktype
device
+struct device *parent
+struct bus_type *bus
+struct device_driver *driver
+struct kobject kobj
device_driver
+char *name
+struct bus_type *bus
+int(*probe)(struct device *)
bus_type
+char *name
+int(*match)(struct device *, struct device_driver *)

六、设备模型工作流程

1. 设备注册流程
设备总线驱动device_register()添加到总线设备链表遍历驱动链表调用match()probe()设备绑定设备与驱动等待后续驱动注册alt[匹配成功][匹配失败]设备总线驱动
2. 驱动注册流程
驱动总线设备driver_register()添加到总线驱动链表遍历设备链表调用match()执行probe()绑定设备与驱动alt[匹配成功]驱动总线设备

七、最小化代码实例(Platform设备/驱动)

场景:实现一个虚拟平台设备(my_device)和驱动(my_driver

1. 设备端代码 (my_device.c):

#include <linux/module.h>
#include <linux/platform_device.h>static struct platform_device my_device = {.name = "my_device",   // 匹配驱动名称.id = -1,
};static int __init my_device_init(void) {platform_device_register(&my_device);printk("My device registered\n");return 0;
}static void __exit my_device_exit(void) {platform_device_unregister(&my_device);printk("My device unregistered\n");
}module_init(my_device_init);
module_exit(my_device_exit);
MODULE_LICENSE("GPL");

2. 驱动端代码 (my_driver.c):

#include <linux/module.h>
#include <linux/platform_device.h>static int my_probe(struct platform_device *pdev) {printk("Device probed! Driver attached.\n");return 0;
}static int my_remove(struct platform_device *pdev) {printk("Device removed. Driver detached.\n");return 0;
}static struct platform_driver my_driver = {.driver = {.name = "my_device",  // 匹配设备名称.owner = THIS_MODULE,},.probe = my_probe,.remove = my_remove,
};module_platform_driver(my_driver); // 自动注册/注销驱动
MODULE_LICENSE("GPL");

3. 测试步骤

# 编译加载模块
sudo insmod my_device.ko
sudo insmod my_driver.ko# 查看日志
dmesg | tail
# 输出示例:
# [  123.456] My device registered
# [  124.789] Device probed! Driver attached# 查看 sysfs 结构
ls /sys/bus/platform/devices/my_device
# 包含:driver, power, subsystem 等符号链接# 卸载模块
sudo rmmod my_driver my_device

八、调试工具与命令

1. SysFS 关键路径
路径作用
/sys/bus/所有总线类型
/sys/devices/设备物理层次结构
/sys/class/按功能分类的设备视图
/sys/kernel/debug/devices_deferred延迟探测的设备列表
2. 关键命令
# 查看设备树
ls -l /sys/devices/# 查看总线绑定关系
cat /sys/bus/platform/devices/my_platdev/driver# 动态打印内核消息
dmesg -w | grep "my_platdev"# 触发设备探测(手动绑定)
echo my_platdev > /sys/bus/platform/drivers/my_platdev/bind# 查看设备资源信息
cat /proc/iomem | grep my_platdev
3. DebugFS 调试
# 查看设备引用计数
cat /sys/kernel/debug/kobject/my_platdev/kref# 跟踪设备事件
echo 1 > /sys/kernel/debug/tracing/events/device/enable
cat /sys/kernel/debug/tracing/trace_pipe

九、核心机制深度解析

1. kobject 生命周期管理
struct kobject *kobj;
kobject_init(kobj, &my_ktype);   // 初始化引用计数为1
kobject_add(kobj, parent, "name"); // 添加到sysfs
kobject_put(kobj);               // 减少引用计数,为0时调用release()
2. 设备-驱动匹配逻辑

总线match()函数典型实现:

static int platform_match(struct device *dev, struct device_driver *drv)
{return strcmp(dev_name(dev), drv->name) == 0;
}
3. SysFS 属性操作
static ssize_t status_show(struct device *dev, struct device_attribute *attr, char *buf)
{return sprintf(buf, "%s\n", get_status(dev));
}
static DEVICE_ATTR_RO(status); // 创建只读属性 /sys/devices/.../status

十、常见问题调试技巧

1. Sysfs 导航工具

# 查看设备层次
tree /sys/devices/ | less# 查看总线列表
ls /sys/bus/# 查看设备绑定状态
cat /sys/bus/platform/devices/my_device/driver
# 输出应指向 /sys/bus/platform/drivers/my_device

2. Uevent 调试

# 监控内核事件
udevadm monitor -k -p
# 触发事件(测试热插拔)
echo 1 > /sys/bus/platform/devices/my_device/uevent

3. 动态调试

// 在驱动代码中添加
#include <linux/dynamic_debug.h>
#define dev_dbg(dev, fmt, ...) dynamic_dev_dbg(dev, fmt, ##__VA_ARGS__)
# 启用动态调试
echo "file my_driver.c +p" > /sys/kernel/debug/dynamic_debug/control

4. Ftrace 跟踪

# 跟踪设备注册过程
echo function_graph > /sys/kernel/debug/tracing/current_tracer
echo "bus_register device_add driver_register" > set_ftrace_filter
echo 1 > /sys/kernel/debug/tracing/tracing_on
# 加载模块后查看 trace
cat trace

5. KDB/KGDB

# 在内核崩溃时检查设备状态
kdb> lsdev   # 列出所有设备
kdb> drvlist # 列出驱动

6. 匹配失败排查

  • 检查 /sys/bus/xxx/devicesdrivers 目录是否存在设备/驱动
  • 确认 match() 函数返回值(需返回 1 表示匹配)

7. Probe 失败分析

  • probe 函数添加 -EPROBE_DEFER 实现依赖重试
  • 使用 dev_err(&pdev->dev, "Error message") 输出详细错误

8. 内存泄漏检测

# 检查 kobject 引用
grep my_device /sys/kernel/debug/kobject_leak

9. Sysfs 属性调试

// 添加可读写属性
static ssize_t status_show(struct device *dev, struct device_attribute *attr, char *buf) {return sprintf(buf, "OK\n");
}
static DEVICE_ATTR_RO(status); // 创建 /sys/devices/.../my_device/status
总结

Linux 设备模型通过四大核心机制(对象抽象、自动匹配、sysfs 接口、热插拔)实现统一设备管理。开发者需掌握:

  • 总线/设备/驱动的注册流程
  • kobject 的生命周期管理
  • probe/remove 的调用时机
  • Sysfs 调试工具链
    实际开发中建议结合 devres API 管理资源,并善用动态调试提高效率。

最终输出:包含 2 个可编译模块的完整代码包(需替换 my_device/my_driver 为实际名称),可通过 Makefile 集成到内核构建系统。

http://www.lryc.cn/news/624167.html

相关文章:

  • Rust Async 异步编程(五):执行器和系统 I/O
  • Python可视化工具-Bokeh:动态显示数据
  • java_spring boot 中使用 log4j2 及 自定义layout设置示例
  • 【Java后端】MyBatis-Plus 原理解析
  • 股票术语:“支撑位”
  • 链表OJ题讲解---试金石含金量
  • qt svg缺失元素, 原因是不支持 rgba
  • 测试Windows10IoT系统是否可以正常运行KingSCSDA3.8软件
  • JavaScirpt高级程序设计第三版学习查漏补缺(1)
  • JavaScript 中constructor 属性的指向异常问题
  • 【前端面试题】JavaScript核心面试题解析
  • 芋道RBAC实现介绍
  • 软件开发 - foreground 与 background
  • 数据结构与算法之 leetcode 98. 验证二叉搜索树 (前序,中序,后序遍历)
  • React 基础实战:从组件到案例全解析
  • Wasserstein GAN:如何解决GANS训练崩溃,深入浅出数学原理级讲解WGAN与WGAN-GP
  • C语言相关简单数据结构:双向链表
  • 【数据分享】黑龙江省黑土区富锦市土地利用数据
  • 正则表达式实用面试题与代码解析专栏
  • 【Linux系列】常见查看服务器 IP 的方法
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘imageio’问题
  • Go语言企业级权限管理系统设计与实现
  • 2024年08月13日 Go生态洞察:Go 1.23 发布与全面深度解读
  • pandas series常用函数
  • leetcode热题100——day33
  • Python 内置模块 collections 常用工具
  • (机器学习)监督学习 vs 非监督学习
  • 二分查找(Binary Search)
  • 机器学习算法篇(十三)------词向量转化的算法思想详解与基于词向量转换的文本数据处理的好评差评分类实战(NPL基础实战)
  • 第七十九:AI的“急诊科医生”:模型失效(Loss Explode)的排查技巧——从“炸弹”到“稳定”的训练之路!