团队博客: 汽车电子社区
概述
Linux设备驱动核心框架是整个Linux驱动子系统的基础设施,提供了统一的设备模型、驱动管理、总线抽象和设备生命周期管理机制。这个框架通过精心设计的面向对象架构,将复杂的硬件抽象为统一的设备对象,为各类驱动程序提供标准化的接口和管理机制。设备核心框架不仅简化了驱动开发,还确保了系统的稳定性、可维护性和可扩展性。本文将从软件架构、调用流程和源码分析三个维度,深入剖析设备驱动核心框架的设计理念和实现机制。
1. 软件架构分析
1.1 设备驱动核心整体架构
Linux设备驱动核心框架采用分层架构设计,从底层的硬件抽象到上层的用户空间接口,形成了完整的设备管理体系。这种分层架构确保了设备模型的一致性和可扩展性。
1.2 核心数据结构架构
设备驱动核心框架的核心是基于kobject的统一设备模型,通过精心设计的结构体层次实现设备的抽象和管理。
1.3 设备链接和依赖关系
设备链接机制是现代Linux设备管理的重要特性,用于表达设备间的依赖关系和初始化顺序。
2. 调用流程分析
2.1 设备注册和发现流程
设备注册是设备生命周期的起点,涉及设备对象的创建、属性设置、总线匹配和驱动绑定等一系列复杂过程。
2.2 驱动注册和绑定流程
驱动注册和绑定是设备模型的核心机制,确保正确的驱动与设备建立关联。
2.3 设备链接建立流程
设备链接机制确保设备间的依赖关系得到正确处理,特别是在复杂的现代系统中。
2.4 电源管理流程
设备电源管理是现代系统的重要组成部分,支持系统级别的挂起恢复和运行时电源管理。
3. 源码深度分析
3.1 核心数据结构源码分析
3.1.1 设备结构体(struct device)
// include/linux/device.h
/**
* struct device - 设备模型的基本设备结构
* @parent: 设备的父设备
* @p: 设备的私有数据,对驱动核心可见
* @init_name: 设备的初始名称
* @type: 设备类型,包含额外的语义信息
* @mutex: 设备操作的互斥锁
* @bus: 设备所属的总线类型
* @driver: 绑定到设备的驱动程序
* @platform_data: 平台特定的数据
* @driver_data: 驱动程序私有数据
* @links: 设备链接信息
* @power: 电源管理信息
* @msi: MSI中断信息
* @of_node: 设备树节点
* @fwnode: 固件节点
* @devt: 设备号(主:次)
*/
struct device {
struct device *parent;
struct device_private *p;
const char *init_name; /* 初始设备名称 */
const struct device_type *type;
struct mutex mutex; /* 互斥锁保护设备状态 */
struct bus_type *bus; /* 设备所属总线类型 */
struct device_driver *driver; /* 绑定到设备的驱动 */
void *platform_data; /* 平台特定数据 */
void *driver_data; /* 驱动私有数据 */
/*
* 设备链接用于表示设备间的依赖关系
*/
struct dev_links_info links;
/*
* 电源管理信息
*/
struct dev_pm_info power;
/*
* MSI中断信息
*/
struct dev_msi_info msi;
/*
* 设备树和固件节点
*/
struct device_node *of_node; /* 设备树节点 */
struct fwnode_handle *fwnode; /* 固件节点 */
/*
* 设备号(用于字符设备和块设备)
*/
dev_t devt; /* 设备号 */
/*
* 设备的kobject基础
*/
struct kobject kobj;
/*
* 设备的类和DMA信息
*/
struct class *class;
const struct attribute_group **groups; /* 设备属性组 */
void *release_data; /* 释放数据 */
/*
* 引用计数和状态
*/
struct kref kref; /* 引用计数 */
struct completion offline_compl; /* 离线完成等待 */
struct list_head deferred_probe; /* 延迟探测链表 */
/*
* 设备状态标志
*/
u32 offline_disabled:1; /* 离线已禁用 */
u32 offline_notified:1; /* 离线已通知 */
u32 of_node_reused:1; /* 设备树节点重用 */
u32 state_synced:1; /* 状态已同步 */
u32 can_match:1; /* 可以匹配 */
u32 early_init:1; /* 早期初始化 */
u32 dma_coherent:1; /* DMA一致性 */
#ifdef CONFIG_DMA_ACCEL
struct list_head dma_node;
struct dentry *dmap;
#endif
};
分析说明:
- parent和kobj构成了设备的层次结构,支持设备树的组织
- bus和driver建立了设备与总线、驱动的关联关系
- links结构管理设备间的依赖关系,是现代设备管理的重要特性
- power结构集成电源管理功能,支持复杂的电源状态转换
- of_node和fwnode支持设备树和ACPI等固件描述机制
3.1.2 设备驱动结构体(struct device_driver)
// include/linux/device.h
/**
* struct device_driver - 设备驱动程序的基本结构
* @name: 驱动程序的名称
* @bus: 驱动程序所属的总线类型
* @owner: 拥有此驱动程序的模块
* @mod_name: 模块名称(如果存在)
* @suppress_bind_attrs: 禁止绑定/解绑属性
* @probe_type: 探测类型(同步/异步)
* @probe: 探测函数,用于绑定设备
* @remove: 移除函数,用于解绑设备
* @shutdown: 关机函数,用于系统关机
* @suspend: 挂起函数,用于电源管理
* @resume: 恢复函数,用于电源管理
* @groups: 驱动程序属性组
* @pm: 电源管理操作
*/
struct device_driver {
const char *name; /* 驱动程序名称 */
struct bus_type *bus; /* 所属总线类型 */
struct module *owner; /* 拥有模块 */
const char *mod_name; /* 模块名称 */
bool suppress_bind_attrs; /* 禁止绑定属性 */
enum probe_type probe_type; /* 探测类型 */
/*
* 驱动程序生命周期回调函数
*/
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); /* 恢复函数 */
/*
* 驱动程序属性和电源管理
*/
const struct attribute_group **groups; /* 属性组 */
const struct dev_pm_ops *pm; /* 电源管理操作 */
};
/*
* 探测类型枚举
*/
enum probe_type {
PROBE_DEFAULT_STRATEGY, /* 默认探测策略 */
PROBE_FORCE_SYNCHRONOUS, /* 强制同步探测 */
PROBE_FORCE_ASYNCHRONOUS, /* 强制异步探测 */
};
/*
* 电源管理消息结构
*/
struct pm_message {
int event; /* 电源管理事件类型 */
int flags; /* 电源管理标志 */
};
/* 常用电源管理事件 */
#define PM_EVENT_SUSPEND 0x0002 /* 系统挂起 */
#define PM_EVENT_RESUME 0x0003 /* 系统恢复 */
#define PM_EVENT_FREEZE 0x0004 /* 系统冻结 */
#define PM_EVENT_QUIESCE 0x0005 /* 系统静止 */
#define PM_EVENT_HIBERNATE 0x0006 /* 系统休眠 */
#define PM_EVENT_THAW 0x0007 /* 系统解冻 */
#define PM_EVENT_RESTORE 0x0008 /* 系统恢复 */
#define PM_EVENT_RECOVER 0x0009 /* 系统恢复 */
分析说明:
- probe和remove是驱动程序的核心回调,实现设备的初始化和清理
- shutdown函数处理系统关机时的设备清理工作
- suspend和resume提供完整的电源管理支持
- probe_type支持同步和异步两种探测模式,优化启动性能
- pm指针指向详细的电源管理操作结构
3.1.3 总线类型结构体(struct bus_type)
// include/linux/device.h
/**
* struct bus_type - 总线类型的抽象表示
* @name: 总线类型的名称
* @dev_name: 设备名称前缀
* @dev_root: 总线根设备
* @dev_groups: 设备默认属性组
* @drv_groups: 驱动默认属性组
* @match: 设备与驱动匹配函数
* @uevent: 生成uevent环境变量
* @probe: 设备探测函数
* @remove: 设备移除函数
* @shutdown: 设备关机函数
* @suspend: 设备挂起函数
* @resume: 设备恢复函数
* @sync_state: 同步状态回调
* @pm: 电源管理操作
*/
struct bus_type {
const char *name; /* 总线类型名称 */
const char *dev_name; /* 设备名称前缀 */
const char *dev_root; /* 总线根设备名称 */
const struct attribute_group **dev_groups; /* 设备属性组 */
const struct attribute_group **drv_groups; /* 驱动属性组 */
/*
* 总线核心回调函数
*/
int (*match)(struct device *dev, struct device_driver *drv); /* 匹配函数 */
int (*uevent)(struct device *dev, struct kobj_uevent_env *env); /* uevent生成 */
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); /* 恢复 */
void (*sync_state)(struct device *dev); /* 同步状态 */
/*
* 电源管理操作
*/
const struct dev_pm_ops *pm; /* 电源管理操作 */
/*
* 总线特定的I/O DMA操作
*/
const struct iommu_ops *iommu_ops; /* IOMMU操作 */
/*
* 私有数据区域
*/
struct subsys_private *p; /* 总线私有数据 */
struct lock_class_key lock_key; /* 锁类键 */
};
分析说明:
- match函数是总线类型的核心,定义了设备和驱动如何匹配
- uevent函数生成设备变化事件,通知用户空间
- probe和remove提供总线级别的设备管理
- sync_state是新增的回调,用于设备状态同步
- iommu_ops支持内存管理单元的操作抽象
3.2 核心函数源码分析
3.2.1 设备注册核心函数
// drivers/base/core.c
/**
* device_register - 注册设备到设备模型
* @dev: 要注册的设备结构体
*
* 这个函数完成设备的完整注册过程,包括初始化、添加到系统、
* 匹配驱动等步骤。成功返回0,失败返回错误码。
*/
int device_register(struct device *dev)
{
int error;
/*
* 初始化设备结构体的基本字段
* 包括kobject、引用计数、状态等
*/
device_initialize(dev);
/*
* 将设备添加到系统中
* 这个函数完成实际的注册过程
*/
error = device_add(dev);
if (error)
goto err_put;
return 0;
err_put:
/*
* 如果注册失败,减少设备引用计数
*/
put_device(dev);
return error;
}
EXPORT_SYMBOL_GPL(device_register);
/**
* device_initialize - 初始化设备结构体
* @dev: 要初始化的设备结构体
*
* 这个函数设置设备的基本属性,为后续的注册做准备。
*/
void device_initialize(struct device *dev)
{
/*
* 初始化kobject
* kobject是设备模型的基础,提供引用计数、sysfs支持等
*/
kobject_init(&dev->kobj, &device_ktype);
/*
* 初始化引用计数
*/
kref_init(&dev->kref);
/*
* 初始化互斥锁
* 保护设备状态变更的并发访问
*/
mutex_init(&dev->mutex);
/*
* 初始化设备链接信息
*/
INIT_LIST_HEAD(&dev->links.consumers);
INIT_LIST_HEAD(&dev->links.suppliers);
dev->links.need_for_probe = 0;
dev->links.defer_sync = false;
/*
* 初始化电源管理信息
*/
dev->power.is_prepared = false;
dev->power.is_suspended = false;
dev->power.is_noirq_suspended = false;
dev->power.is_late_suspended = false;
/*
* 初始化设备的状态标志
*/
dev->state_initialized = 1;
/*
* 初始化延迟探测链表
*/
INIT_LIST_HEAD(&dev->deferred_probe);
/*
* 设置默认的DMA配置
*/
dev->dma_coherent = false;
#ifdef CONFIG_ARCH_HAS_DMA_COHERENCE
arch_setup_dma_ops(dev);
#endif
}
EXPORT_SYMBOL_GPL(device_initialize);
/**
* device_add - 将设备添加到系统中
* @dev: 要添加的设备结构体
*
* 这个函数是设备注册的核心,完成设备的实际添加过程。
*/
int device_add(struct device *dev)
{
struct device *parent = dev->parent;
struct kobject *kobj;
struct class_interface *class_intf;
int error = -EINVAL;
/*
* 检查设备名称
* 每个设备都必须有名称
*/
if (!dev || !dev->init_name || !dev->kobj.kset) {
error = -ENODEV;
goto done;
}
/*
* 获取设备的父节点kobject
* 如果没有指定父设备,使用虚拟设备父节点
*/
kobj = get_device_parent(dev, parent);
if (IS_ERR(kobj)) {
error = PTR_ERR(kobj);
goto done;
}
/*
* 设置kobject的名称
*/
dev->kobj.parent = kobj;
error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->init_name);
if (error)
goto done;
/*
* 设置设备类型
*/
if (dev->type && dev->type->pm) {
dev->pm_domain = dev->type->pm;
}
/*
* 创建设备的sysfs属性文件
*/
error = device_create_file(dev, &dev_attr_uevent);
if (error)
goto attr_error;
/*
* 创建设备类型特定的属性
*/
if (dev->type) {
error = device_create_file(dev, &dev_attr_type);
if (error)
goto uevent_error;
error = device_create_sysfs_entry(dev);
if (error)
goto attr_type_error;
}
/*
* 将设备添加到总线
*/
if (dev->bus) {
error = bus_add_device(dev);
if (error)
goto bus_error;
/*
* 通知总线有新设备
*/
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_ADD_DEVICE, dev);
/*
* 尝试匹配驱动
*/
device_probe(dev);
}
/*
* 将设备添加到类
*/
if (dev->class) {
mutex_lock(&dev->class->p->mutex);
/*
* 将设备添加到类的设备列表
*/
klist_add_tail(&dev->knode_class, &dev->class->p->klist_devices);
/*
* 通知类接口
*/
list_for_each_entry(class_intf, &dev->class->p->interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
mutex_unlock(&dev->class->p->mutex);
}
/*
* 创建设备节点(devtmpfs)
*/
device_create_devtmpfs(dev);
/*
* 发送uevent通知用户空间
*/
kobject_uevent(&dev->kobj, KOBJ_ADD);
/*
* 增加设备引用计数
*/
get_device(dev);
done:
put_device(parent);
return error;
bus_error:
if (dev->type)
device_remove_file(dev, &dev_attr_type);
attr_type_error:
device_remove_file(dev, &dev_attr_type);
uevent_error:
device_remove_file(dev, &dev_attr_uevent);
attr_error:
kobject_del(&dev->kobj);
goto done;
}
EXPORT_SYMBOL_GPL(device_add);
分析说明:
- device_initialize完成设备的基础初始化,设置kobject、锁、状态等
- device_add完成实际的设备添加,包括sysfs创建、总线匹配、类管理
- 函数中包含完整的错误处理路径,确保失败时正确清理资源
- 设备链接的初始化为现代设备的依赖关系管理提供基础
- uevent机制确保用户空间能够及时响应设备变化
3.2.2 驱动注册核心函数
// drivers/base/driver.c
/**
* driver_register - 注册驱动程序
* @drv: 要注册的驱动结构体
*
* 这个函数将驱动程序添加到系统中,并尝试匹配设备。
*/
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
/*
* 检查驱动参数
*/
if (!drv->bus || !drv->name) {
WARN(1, "Driver '%s' was unable to register.\n", drv->name);
return -EINVAL;
}
/*
* 检查驱动名称是否已存在
* 避免在同一总线上注册同名驱动
*/
other = driver_find(drv->name, drv->bus);
if (other) {
put_driver(other);
pr_err("Error: Driver '%s' is already registered, aborting...\n",
drv->name);
return -EBUSY;
}
/*
* 初始化驱动的kobject
*/
drv->p = kzalloc(sizeof(*drv->p), GFP_KERNEL);
if (!drv->p)
return -ENOMEM;
/*
* 初始化驱动的设备列表
*/
klist_init(&drv->p->klist_devices, NULL, NULL);
/*
* 将驱动添加到总线
*/
ret = bus_add_driver(drv);
if (ret)
return ret;
/*
* 添加驱动到模块系统
*/
ret = driver_add_groups(drv, drv->groups);
if (ret)
bus_remove_driver(drv);
return ret;
}
EXPORT_SYMBOL_GPL(driver_register);
/**
* bus_add_driver - 将驱动添加到总线
* @drv: 要添加的驱动
*
* 这个函数处理驱动在总线上的注册,包括创建sysfs目录、
* 设置属性、触发设备探测等。
*/
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus = drv->bus;
struct driver_private *priv;
int error = 0;
/*
* 分配驱动私有结构
*/
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
/*
* 创建驱动的kobject
*/
priv->kobj.kset = bus->p->drivers_kset;
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;
/*
* 创建驱动属性
*/
if (drv->mod_name) {
error = driver_create_file(drv, &driver_attr_mod_name);
if (error)
goto out_del_kobj;
}
/*
* 创建uevent属性
*/
error = driver_create_file(drv, &driver_attr_uevent);
if (error)
goto out_del_mod_name;
/*
* 创建绑定/解绑属性
*/
error = driver_create_file(drv, &driver_attr_bind);
if (error)
goto out_del_uevent;
error = driver_create_file(drv, &driver_attr_unbind);
if (error)
goto out_del_bind;
/*
* 将驱动添加到总线的驱动列表
*/
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
/*
* 触发设备探测
* 尝试为总线上未绑定的设备匹配这个驱动
*/
if (drv->bus->p->drivers_autoprobe) {
driver_attach(drv);
}
/*
* 添加到模块系统
*/
module_add_driver(drv->owner, drv);
return 0;
out_del_bind:
driver_remove_file(drv, &driver_attr_bind);
out_del_uevent:
driver_remove_file(drv, &driver_attr_uevent);
out_del_mod_name:
if (drv->mod_name)
driver_remove_file(drv, &driver_attr_mod_name);
out_del_kobj:
kobject_put(&priv->kobj);
out_unregister:
kfree(drv->p);
drv->p = NULL;
return error;
}
/**
* driver_attach - 尝试将驱动绑定到总线上所有未绑定设备
* @drv: 要绑定的驱动
*
* 这个函数遍历总线上的所有设备,尝试匹配并绑定。
*/
int driver_attach(const struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, (void *)drv, __driver_attach);
}
/**
* __driver_attach - 尝试绑定驱动到特定设备
* @dev: 要绑定设备
* @data: 驱动数据
*
* 这是driver_attach的实际实现函数。
*/
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;
int ret;
/*
* 检查设备是否已经绑定到驱动
*/
if (dev->driver)
return 0;
/*
* 获取设备锁,保护设备状态
*/
device_lock(dev);
/*
* 再次检查设备状态,可能在获取锁期间发生变化
*/
if (dev->driver) {
device_unlock(dev);
return 0;
}
/*
* 检查驱动是否匹配设备
*/
if (!driver_match_device(drv, dev)) {
device_unlock(dev);
return 0;
}
/*
* 尝试绑定驱动到设备
*/
if (!dev->can_match) {
dev->can_match = true;
driver_deferred_probe_add(dev);
device_unlock(dev);
return 0;
}
/*
* 执行实际的绑定操作
*/
ret = device_driver_attach(drv, dev);
if (ret < 0)
dev_err(dev, "Driver attach failed: %d\n", ret);
else
ret = 0;
device_unlock(dev);
return ret;
}
分析说明:
- driver_register完成驱动的完整注册过程,包括参数验证、冲突检查
- bus_add_driver处理驱动在总线上的具体注册,包括sysfs创建
- driver_attach尝试将驱动绑定到所有可能的设备,实现自动发现
- 错误处理路径确保注册失败时的资源正确清理
- 并发安全通过设备锁和原子操作保证
3.2.3 设备绑定核心函数
// drivers/base/dd.c
/**
* device_driver_attach - 尝试绑定驱动到设备
* @drv: 要绑定的驱动
* @dev: 要绑定的设备
*
* 这个函数执行实际的设备和驱动绑定操作。
*/
int device_driver_attach(const struct device_driver *drv, struct device *dev)
{
int ret = 0;
/*
* 调用总线的探测函数
*/
if (drv->bus->probe) {
ret = drv->bus->probe(dev);
if (ret) {
dev_warn(dev, "Bus probe failed: %d\n", ret);
goto out;
}
} else if (drv->probe) {
/*
* 如果总线没有probe函数,调用驱动的probe函数
*/
ret = drv->probe(dev);
if (ret) {
dev_warn(dev, "Driver probe failed: %d\n", ret);
goto out;
}
}
/*
* 绑定成功,建立设备和驱动的关联
*/
device_bind_driver(dev);
out:
return ret;
}
/**
* device_bind_driver - 将驱动绑定到设备
* @dev: 要绑定的设备
*
* 这个函数建立设备和驱动的正式关联关系。
*/
int device_bind_driver(struct device *dev)
{
int ret;
/*
* 将设备添加到驱动的设备列表
*/
ret = driver_sysfs_add(dev);
if (ret)
return ret;
/*
* 设置设备的驱动指针
*/
device_links_driver_bound(dev);
device_pm_bind(dev);
/*
* 设置设备的驱动引用
*/
dev->driver = dev->driver;
/*
* 更新设备链接状态
*/
device_links_force_bind(dev);
/*
* 通知总线设备已绑定
*/
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_BOUND_DRIVER, dev);
/*
* 创建设备绑定属性
*/
klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
/*
* 通知类接口
*/
if (dev->class) {
mutex_lock(&dev->class->p->mutex);
list_for_each_entry(class_intf, &dev->class->p->interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
mutex_unlock(&dev->class->p->mutex);
}
return 0;
}
/**
* device_unbind_driver - 解绑设备驱动
* @dev: 要解绑的设备
*
* 这个函数解除设备和驱动的关联关系。
*/
void device_unbind_driver(struct device *dev)
{
struct device_driver *drv = dev->driver;
if (!drv)
return;
/*
* 从驱动的设备列表中移除
*/
klist_remove(&dev->p->knode_driver);
/*
* 清理设备链接
*/
device_links_driver_cleanup(dev);
/*
* 清理电源管理
*/
device_pm_remove(dev);
/*
* 清理sysfs
*/
driver_sysfs_remove(dev);
/*
* 清除驱动指针
*/
device_set_driver(dev, NULL);
/*
* 通知总线
*/
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_UNBOUND_DRIVER, dev);
/*
* 调用总线的remove函数
*/
if (drv->bus && drv->bus->remove)
drv->bus->remove(dev);
/*
* 调用驱动的remove函数
*/
else if (drv->remove)
drv->remove(dev);
/*
* 通知类接口
*/
if (dev->class) {
mutex_lock(&dev->class->p->mutex);
list_for_each_entry(class_intf, &dev->class->p->interfaces, node)
if (class_intf->remove_dev)
class_intf->remove_dev(dev, class_intf);
mutex_unlock(&dev->class->p->mutex);
}
}
分析说明:
- device_driver_attach是设备绑定的核心入口,负责调用探测函数
- device_bind_driver建立正式的绑定关系,更新各种数据结构
- 设备链接管理确保绑定顺序的正确性
- 通知机制确保总线和类接口了解绑定状态变化
- 解绑操作清理所有相关资源,保持系统状态一致性
4. 高级特性和优化机制
4.1 设备链接机制深度分析
设备链接是Linux设备模型的现代特性,用于管理设备间的复杂依赖关系。
// drivers/base/core.c
/**
* device_link_add - 添加设备链接
* @consumer: 消费者设备
* @supplier: 供应者设备
* @flags: 链接标志
*
* 这个函数在两个设备间建立依赖关系,确保供应者优先于消费者
* 进行初始化和管理。
*/
struct device_link *device_link_add(struct device *consumer,
struct device *supplier, u32 flags)
{
struct device_link *link;
/*
* 验证输入参数
*/
if (!consumer || !supplier ||
consumer == supplier ||
WARN_ON(consumer->links.status != DL_DEV_NO_DRIVER &&
consumer->links.status != DL_DEV_PROBING) ||
WARN_ON(supplier->links.status != DL_DEV_NO_DRIVER &&
supplier->links.status != DL_DEV_PROBING &&
supplier->links.status != DL_DEV_DRIVER_BOUND))
return NULL;
/*
* 检查是否已存在链接
*/
list_for_each_entry(link, &supplier->links.consumers, s_node) {
if (link->consumer == consumer) {
/*
* 更新现有链接的标志
*/
link->flags |= flags;
return link;
}
}
/*
* 分配新的设备链接
*/
link = kzalloc(sizeof(*link), GFP_KERNEL);
if (!link)
return NULL;
/*
* 初始化链接结构
*/
link->supplier = supplier;
link->consumer = consumer;
link->flags = flags;
INIT_LIST_HEAD(&link->s_node);
INIT_LIST_HEAD(&link->c_node);
/*
* 根据标志设置链接状态
*/
if (flags & DL_FLAG_STATELESS)
link->status = DL_STATE_NONE;
else
link->status = DL_STATE_DORMANT;
/*
* 添加到供应商和消费者的链接列表
*/
list_add_tail(&link->s_node, &supplier->links.consumers);
list_add_tail(&link->c_node, &consumer->links.suppliers);
/*
* 如果是管理状态链接,处理电源管理依赖
*/
if (!(flags & DL_FLAG_STATELESS)) {
/*
* 设置管理状态
*/
if (supplier->links.status == DL_DEV_DRIVER_BOUND &&
consumer->links.status == DL_DEV_DRIVER_BOUND) {
link->status = DL_STATE_ACTIVE;
}
/*
* 处理电源管理同步
*/
if (flags & DL_FLAG_PM_RUNTIME) {
pm_runtime_get_sync(supplier);
pm_runtime_get_sync(consumer);
link->rpm_active = true;
}
}
return link;
}
EXPORT_SYMBOL_GPL(device_link_add);
/**
* device_link_del - 删除设备链接
* @link: 要删除的设备链接
*
* 删除之前创建的设备链接,清理所有相关资源。
*/
void device_link_del(struct device_link *link)
{
if (!link)
return;
/*
* 从供应商和消费者的链接列表中移除
*/
list_del(&link->s_node);
list_del(&link->c_node);
/*
* 清理运行时电源管理引用
*/
if (link->rpm_active) {
pm_runtime_put_sync(link->supplier);
pm_runtime_put_sync(link->consumer);
}
/*
* 释放链接结构
*/
kfree(link);
}
EXPORT_SYMBOL_GPL(device_link_del);
4.2 延迟探测机制
延迟探测机制处理设备驱动依赖的复杂情况,当设备无法立即找到合适的驱动时进行延迟处理。
// drivers/base/dd.c
/**
* driver_deferred_probe_add - 将设备添加到延迟探测列表
* @dev: 要延迟探测的设备
*
* 当设备无法立即找到合适的驱动时,将设备加入延迟探测列表。
*/
void driver_deferred_probe_add(struct device *dev)
{
mutex_lock(&deferred_probe_mutex);
/*
* 检查设备是否已经在延迟探测列表中
*/
if (list_empty(&dev->deferred_probe)) {
/*
* 将设备添加到延迟探测列表
*/
dev_info(dev, "Added to deferred probe list\n");
list_add_tail(&dev->deferred_probe, &deferred_probe_pending_list);
/*
* 设置延迟探测原因
*/
dev_set_deferred_probe_reason(dev, NULL);
}
mutex_unlock(&deferred_probe_mutex);
}
/**
* driver_deferred_probe_trigger - 触发延迟探测
*
* 这个函数尝试重新探测所有延迟的设备。
*/
void driver_deferred_probe_trigger(void)
{
struct device *dev;
struct list_head local_list;
/*
* 移动所有延迟设备到本地列表
* 减少锁的持有时间
*/
INIT_LIST_HEAD(&local_list);
mutex_lock(&deferred_probe_mutex);
list_splice_init(&deferred_probe_pending_list, &local_list);
mutex_unlock(&deferred_probe_mutex);
/*
* 遍历延迟设备列表
*/
list_for_each_entry(dev, &local_list, deferred_probe) {
/*
* 从延迟列表中移除
*/
list_del_init(&dev->deferred_probe);
/*
* 设置设备状态为可以匹配
*/
dev->can_match = true;
/*
* 尝试探测设备
*/
device_probe(dev);
/*
* 如果探测失败,重新加入延迟列表
*/
if (dev->driver)
continue;
mutex_lock(&deferred_probe_mutex);
list_add_tail(&dev->deferred_probe, &deferred_probe_pending_list);
mutex_unlock(&deferred_probe_mutex);
}
/*
* 设置下次延迟探测的超时
*/
if (!list_empty(&deferred_probe_pending_list))
schedule_delayed_work(&deferred_probe_work, 10);
}
/**
* deferred_probe_work_func - 延迟探测工作函数
* @work: 工作结构
*
* 这个工作函数定期触发延迟探测。
*/
static void deferred_probe_work_func(struct work_struct *work)
{
driver_deferred_probe_trigger();
}
static DECLARE_DELAYED_WORK(deferred_probe_work, deferred_probe_work_func);
4.3 设备资源管理(devres)
设备资源管理框架简化了驱动程序中资源的分配和释放,避免资源泄漏。
// drivers/base/devres.c
/**
* devm_kzalloc - 托管的内存分配
* @dev: 设备结构
* @size: 分配大小
* @gfp: 分配标志
*
* 这个函数分配内存并自动与设备生命周期绑定,
* 当设备被移除时自动释放内存。
*/
void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)
{
struct devres *dr;
void *ptr;
/*
* 分配内存和资源管理结构
*/
dr = devres_alloc(devm_kzalloc_release, size + sizeof(*dr), gfp);
if (!dr)
return NULL;
/*
* 获取实际的数据区域
*/
ptr = devres_data(dr);
/*
* 将资源添加到设备的资源列表
*/
devres_add(dev, dr);
/*
* 清零内存区域
*/
memset(ptr, 0, size);
return ptr;
}
EXPORT_SYMBOL_GPL(devm_kzalloc);
/**
* devm_kfree - 托管的内存释放
* @dev: 设备结构
* @ptr: 要释放的内存指针
*
* 这个函数释放之前通过devm_kzalloc分配的内存。
*/
void devm_kfree(struct device *dev, const void *ptr)
{
int rc;
/*
* 查找并移除对应的资源
*/
rc = devres_destroy(dev, devm_kzalloc_release,
devm_kzalloc_match, (void *)ptr);
WARN_ON(rc);
}
EXPORT_SYMBOL_GPL(devm_kfree);
/**
* devm_request_irq - 托管的中断请求
* @dev: 设备结构
* @irq: 中断号
* @handler: 中断处理函数
* @irqflags: 中断标志
* @devname: 设备名称
* @dev_id: 设备ID
*
* 这个函数请求中断并与设备生命周期绑定。
*/
int devm_request_irq(struct device *dev, unsigned int irq,
irq_handler_t handler, unsigned long irqflags,
const char *devname, void *dev_id)
{
struct irq_devres *dr;
int rc;
/*
* 分配中断资源管理结构
*/
dr = devres_alloc(devm_irq_release, sizeof(*dr), GFP_KERNEL);
if (!dr)
return -ENOMEM;
/*
* 请求中断
*/
rc = request_irq(irq, handler, irqflags, devname, dev_id);
if (rc) {
devres_free(dr);
return rc;
}
/*
* 保存中断信息到资源结构
*/
dr->irq = irq;
dr->dev_id = dev_id;
/*
* 添加到设备资源列表
*/
devres_add(dev, dr);
return 0;
}
EXPORT_SYMBOL_GPL(devm_request_irq);
/**
* devm_irq_release - 中断资源释放函数
* @dev: 设备结构
* @res: 资源结构
*
* 这个函数在设备移除时自动调用,释放中断资源。
*/
static void devm_irq_release(struct device *dev, void *res)
{
struct irq_devres *dr = res;
free_irq(dr->irq, dr->dev_id);
}
5. 调试和监控机制
5.1 设备模型调试接口
Linux设备模型提供了丰富的调试接口,帮助开发者诊断设备和驱动问题。
// drivers/base/core.c
/**
* device_create_file - 创建设备属性文件
* @dev: 设备结构
* @attr: 属性结构
*
* 在sysfs中创建设备属性文件,用于调试和监控。
*/
int device_create_file(struct device *dev,
const struct device_attribute *attr)
{
int error = 0;
/*
* 检查设备是否已经初始化
*/
if (dev_get_drvdata(dev)) {
error = sysfs_create_file(&dev->kobj, &attr->attr);
} else {
error = -EEXIST;
}
return error;
}
EXPORT_SYMBOL_GPL(device_create_file);
/**
* device_remove_file - 移除设备属性文件
* @dev: 设备结构
* @attr: 属性结构
*
* 从sysfs中移除设备属性文件。
*/
void device_remove_file(struct device *dev,
const struct device_attribute *attr)
{
if (dev_get_drvdata(dev))
sysfs_remove_file(&dev->kobj, &attr->attr);
}
EXPORT_SYMBOL_GPL(device_remove_file);
/**
* device_create_managed_file - 创建托管的属性文件
* @dev: 设备结构
* @attr: 属性结构
*
* 创建自动管理的属性文件,设备移除时自动清理。
*/
int device_create_managed_file(struct device *dev,
const struct device_attribute *attr)
{
int error;
/*
* 创建属性文件
*/
error = device_create_file(dev, attr);
if (error)
return error;
/*
* 添加到托管资源列表
*/
return devm_add_action_or_reset(dev,
(void(*)(void *))device_remove_file,
(void *)attr);
}
EXPORT_SYMBOL_GPL(device_create_managed_file);
/**
* device_show_int - 显示整数属性
* @dev: 设备结构
* @attr: 属性结构
* @buf: 输出缓冲区
*
* 通用的整数属性显示函数。
*/
ssize_t device_show_int(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct dev_ext_attribute *ea = container_of(attr,
struct dev_ext_attribute, attr);
return sprintf(buf, "%d\n", *(int *)(ea->var));
}
EXPORT_SYMBOL_GPL(device_show_int);
/**
* device_store_int - 存储整数属性
* @dev: 设备结构
* @attr: 属性结构
* @buf: 输入缓冲区
* @count: 输入长度
*
* 通用的整数属性存储函数。
*/
ssize_t device_store_int(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct dev_ext_attribute *ea = container_of(attr,
struct dev_ext_attribute, attr);
int ret;
long val;
/*
* 解析输入字符串
*/
ret = kstrtol(buf, 10, &val);
if (ret)
return ret;
/*
* 更新变量值
*/
*(int *)(ea->var) = val;
return count;
}
EXPORT_SYMBOL_GPL(device_store_int);
5.2 系统监控和统计
设备模型提供详细的统计信息,帮助监控系统状态和性能。
// drivers/base/core.c
/**
* device_show_status - 显示设备状态
* @dev: 设备结构
* @attr: 属性结构
* @buf: 输出缓冲区
*
* 显示设备的当前状态信息。
*/
static ssize_t device_show_status(struct device *dev,
struct device_attribute *attr, char *buf)
{
const char *status;
switch (dev->links.status) {
case DL_DEV_NO_DRIVER:
status = "no-driver";
break;
case DL_DEV_PROBING:
status = "probing";
break;
case DL_DEV_DRIVER_BOUND:
status = "bound";
break;
case DL_DEV_UNBINDING:
status = "unbinding";
break;
default:
status = "unknown";
break;
}
return sprintf(buf, "%s\n", status);
}
/**
* device_show_deferred_probe - 显示延迟探测原因
* @dev: 设备结构
* @attr: 属性结构
* @buf: 输出缓冲区
*
* 显示设备延迟探测的原因。
*/
static ssize_t device_show_deferred_probe(struct device *dev,
struct device_attribute *attr,
char *buf)
{
if (dev->p->deferred_probe_reason)
return sprintf(buf, "%s\n", dev->p->deferred_probe_reason);
else
return sprintf(buf, "none\n");
}
/**
* device_show_uevent - 显示uevent信息
* @dev: 设备结构
* @attr: 属性结构
* @buf: 输出缓冲区
*
* 显示设备的uevent信息。
*/
static ssize_t device_show_uevent(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct kobj_uevent_env *env;
int i;
int len = 0;
/*
* 创建uevent环境
*/
env = kzalloc(sizeof(*env), GFP_KERNEL);
if (!env)
return -ENOMEM;
/*
* 生成uevent变量
*/
if (dev->bus && dev->bus->uevent)
dev->bus->uevent(dev, env);
if (dev->class && dev->class->dev_uevent)
dev->class->dev_uevent(dev, env);
/*
* 将uevent变量格式化到缓冲区
*/
for (i = 0; i < env->envp_idx; i++) {
len += sprintf(buf + len, "%s\n", env->envp[i]);
if (len >= PAGE_SIZE)
break;
}
kfree(env);
return len;
}
6. 总结与发展趋势
6.1 设备驱动核心框架的设计优势
Linux设备驱动核心框架经过二十多年的发展,已经成为现代操作系统中最为先进和完善的设备管理系统之一。其设计优势体现在多个维度:
统一抽象模型:通过基于kobject的统一设备模型,将不同类型的硬件设备抽象为统一的设备对象,极大地简化了驱动开发和设备管理的复杂性。这种抽象使得开发者可以用统一的接口处理各种类型的设备。
模块化架构:框架采用高度模块化的设计,设备、驱动、总线、类等核心概念相互独立又紧密协作,为不同类型的设备提供了灵活的扩展机制。这种模块化设计使得添加新的总线类型或设备类型变得简单直接。
自动化管理:通过设备探测、驱动匹配、资源管理等自动化机制,大大减少了驱动开发的复杂性和出错概率。延迟探测机制和设备链接确保了复杂系统中设备初始化的正确顺序。
生命周期管理:完整的设备生命周期管理,从设备注册、驱动绑定到设备移除,都有标准化的处理流程。电源管理的集成使得设备在不同电源状态下都能正确工作。
6.2 技术创新与突破
Linux设备驱动核心框架的技术创新主要体现在以下几个方面:
设备链接机制:设备链接的引入解决了现代复杂系统中设备间依赖关系的管理问题,确保设备初始化的正确顺序,提高了系统启动的可靠性。
延迟探测机制:通过智能的延迟探测机制,处理设备驱动的循环依赖和时序问题,避免了启动过程中的死锁和失败。
设备资源管理:devres框架彻底解决了驱动开发中的资源泄漏问题,通过自动化的资源管理大大提高了驱动程序的健壮性。
运行时电源管理:集成运行时电源管理,使得设备可以在空闲时自动进入低功耗状态,显著改善了系统的能耗效率。
用户空间集成:通过sysfs、uevent等机制,实现了内核设备管理与用户空间工具的无缝集成,支持udev等用户空间工具的自动化管理。
6.3 未来发展趋势
随着硬件技术和应用场景的不断发展,设备驱动核心框架面临着新的挑战和发展机遇:
异构设备支持:GPU、FPGA、AI加速器等异构计算设备的普及要求设备模型提供更好的抽象和管理机制,支持复杂设备组合的统一管理。
安全增强:在云原生和多租户环境中,设备访问的安全隔离变得愈发重要,设备模型需要提供更强的安全机制和访问控制。
容器化设备管理:容器和微服务架构要求设备模型支持更细粒度的设备共享和隔离,为容器提供专用的设备管理能力。
实时性保证:工业物联网和实时控制应用要求设备管理提供更确定的时间特性,包括中断处理延迟、设备响应时间等方面的保证。
AI驱动的设备管理:利用机器学习技术预测设备使用模式,优化设备调度和电源管理,实现更智能的设备管理策略。
边缘计算支持:边缘设备的资源受限特性要求设备模型更加轻量化和高效,支持资源的动态分配和优化。
Linux设备驱动核心框架作为整个Linux系统的基石,其持续的演进和创新将继续为各种计算平台提供稳定可靠的设备管理基础。通过不断适应新的硬件特性和应用需求,设备驱动框架将继续支撑Linux生态系统的发展和壮大。
文档总结:
本文从软件架构、调用流程、源码分析三个维度,对Linux设备驱动核心框架进行了深度剖析。通过详细的架构图、流程图和源码注释,全面展示了设备模型的设计理念、实现机制和优化策略。文档涵盖了设备注册、驱动绑定、设备链接、资源管理、电源管理、调试监控等核心内容,为理解现代Linux设备管理系统提供了完整的技术视角。通过对这些核心概念的深入理解,开发者可以更好地掌握Linux驱动开发的精髓,开发出更加健壮和高效的设备驱动程序。

4114

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



