一个具有正常探测功能的pci驱动程序应具有基本的pci_driver结构实现,如:
static struct pci_driver driver_ops = {
.name = "driver_name", // 驱动名称
.id_table = pci_ids, // 驱动ids结构
.probe = pci_probe, // 驱动探测函数
.remove = pci_remove, // 驱动移除函数
};
其中,驱动ids结构可以按照以下方式实现:
static struct pci_device_id pci_ids[] = {
{ PCI_DEVICE(MANF_ID, MODEL_CODE) },
{ 0 }
};
MANF_ID 表示厂商ID 是一个数字ID,如0xfead 或 PCI_ANY_ID(表示通用),如果有真实硬件应与硬件ID一致
MODEL_CODE 表示厂商设备 是一个数字ID,如0x1234 或 PCI_ANY_ID(表示通用),如上
默认情况下,子系统的厂商ID和厂商设备ID不用设置,它们采用PCI_ANY_ID(表示通用),class、class_mask等成员默认也不需要指定,在设备创建后,创建相关对象关联设备节点即可(或创建时指定父级)
pci_probe:
驱动探测函数,可在函数内部实现bar映射等设备相关的功能设置等等
pci_remove:
驱动移除函数,可在函数内部实现驱动的移除等等,同样也可以实现设备取消bar映射等相关的功能设置
准备工作完成后,我们开始驱动的执行逻辑分析:
通常情况下,我们通过定义module_init(函数名称),作为驱动程序入口函数执行,如pci_init_module:
static int pci_init_module(void)
{
...
如字符、块设备注册,class创建,class设备节点关联等等
驱动其他的一些定义,如设置变量标志,输出注册相关新等等
...
dri_register = pci_register_driver(&driver_ops);
if (dri_register) {
printk(KERN_ERR ": pci driver registration failed !\n");
goto fail;
}
...
return dri_register;
fail:
if(DBUG_PRINT) printk(KERN_ALERT "pci_init_module :failed !\n");
return dri_register;
}
现在分析pci_register_driver函数 :
pci_register_driver(driver) \
__pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
THIS_MODULE 如果驱动编译选项为m或手动编译驱动,在编译时会生成__this_module结构对象,参考 __this_module。如果为y时,则通过"内置模块条目 /sys/modules"查找,参考 module_add_driver
KBUILD_MODNAME 模块名称,编译时通过如obj-m:=pci_test.o中获取pci_test
driver 注册的driver_ops对象
__pci_register_driver函数内部赋值完成后,执行driver_register(&driver_ops->driver); 驱动分配、探测设备,并注册到总线等等
在arm等架构下,pci_register_driver还包括设备树相关的概念流程,如DMA设置,通过开启CONFIG_OF相关编译选项,启动设备树相关功能,用于动态加载dts目录下的配置文件信息
驱动分配、探测并注册到总线
#define pci_register_driver(driver) \
__pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
||
\/
int __pci_register_driver(struct pci_driver *drv, struct module *owner,
const char *mod_name)
{
/* 初始化通用驱动程序字段 */
drv->driver.name = drv->name; // 驱动名称
drv->driver.bus = &pci_bus_type; // 驱动的设备所属的总线
drv->driver.owner = owner; // 所属者
drv->driver.mod_name = mod_name; // 用于内置模块
drv->driver.groups = drv->groups; // 驱动核心自动创建的默认属性
drv->driver.dev_groups = drv->dev_groups; // 设备实例绑定到驱动程序后的附加属性
spin_lock_init(&drv->dynids.lock); // 初始化动态id锁
INIT_LIST_HEAD(&drv->dynids.list); // 初始化动态id链表
/* 注册到核心 */
return driver_register(&drv->driver); // 驱动分配、探测并注册到总线
}
EXPORT_SYMBOL(__pci_register_driver);
pci_driver pci驱动结构
struct pci_driver {
struct list_head node; // 节点
const char *name; // 名称
const struct pci_device_id *id_table; // pci设备id结构
/* 必须为非NULL,才能调用探测 */
int (*probe) (struct pci_dev *dev, const struct pci_device_id *id); /* 探测函数 */
// 已插入设备(硬件),并且pci设备id结构 描述的厂商ID等信息正确,可触发此函数执行
void (*remove) (struct pci_dev *dev); /* 设备移除(如果不是热插拔驱动则为NULL) */
int (*suspend) (struct pci_dev *dev, pm_message_t state); /* 设备挂起 */
int (*suspend_late) (struct pci_dev *dev, pm_message_t state);
int (*resume_early) (struct pci_dev *dev);
int (*resume) (struct pci_dev *dev); /* 唤醒设备 */
void (*shutdown) (struct pci_dev *dev);
int (*sriov_configure) (struct pci_dev *dev, int num_vfs); /* PF pdev */
const struct pci_error_handlers *err_handler; // PCI总线错误事件回调结构
struct device_driver driver; /* 设备驱动结构 */
struct pci_dynids dynids; // 动态id,用于驱动与设备的匹配
// 如果没有找到,再查询静态id
};
pci_device_id pci设备id结构
struct pci_device_id {
__u32 vendor, device; /* 厂商和设备ID or PCI_ANY_ID*/
__u32 subvendor, subdevice; /* 子系统ID or PCI_ANY_ID */
__u32 class, class_mask; /* (class,subclass,prog-if) triplet */
kernel_ulong_t driver_data; /* 驱动程序私有数据 */
};
driver_private 驱动私有结构
struct driver_private {
struct kobject kobj; // 根kobj
struct klist klist_devices; // 设备列表
struct klist_node knode_bus; // 设备节点
struct module_kobject *mkobj; // 模块kobj
struct device_driver *driver; // 设备驱动结构
};
dev_pin_info 设备的引脚状态容器
struct dev_pin_info {
struct pinctrl *p; 引脚控制包含设备的句柄
struct pinctrl_state *default_state; // 句柄的默认状态(如果存在)
struct pinctrl_state *init_state; // 探测时的状态(如果存在)
#ifdef CONFIG_PM
struct pinctrl_state *sleep_state; // 挂起时的状态(如果存在)
struct pinctrl_state *idle_state; // 空闲(运行时挂起)时的状态(如果存在)
#endif
};
devres 设备资源
struct devres {
struct devres_node node; // 设备资源节点
/*
* 一些架构希望对kmalloc缓存执行DMA,并且需要比64位整数的对齐更大的保证对齐
* 因此,我们在这里使用ARCH_KMALLOC_MINALIGN
* 并获得与普通KMALLOC()分配的缓冲区完全相同的对齐方式
*/
u8 __aligned(ARCH_KMALLOC_MINALIGN) data[];
// x86_64 按照 __alignof__(unsigned long long)
};
devres_node 设备资源节点
struct devres_node {
struct list_head entry; // 列表(链表)
dr_release_t release; // 释放函数
const char *name; // 名称
size_t size; // 大小
};
pinctrl 引脚控制(设备引脚控制状态保持器)
struct pinctrl {
struct list_head node; // 全局列表节点
struct device *dev; // 使用此引脚控制的设备
struct list_head states; // 此设备的状态列表
struct pinctrl_state *state; // 当前状态
struct list_head dt_maps; // 从设备树动态解析的映射表块(部分架构不具备设备树概念,此概念相关结构的部分成员不使用)
struct kref users; // 引用计数
};
driver_register 驱动分配、探测并注册到总线
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
BUG_ON(!drv->bus->p); // 子系统私有结构
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown)) // 这种情况应该是已注册驱动
// 通常不指定设备驱动结构,由注册过程中自动完成关联
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
other = driver_find(drv->name, drv->bus); // 按名称查找总线上的设备驱动结构
if (other) { // 如果存在,应该是已注册驱动
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}
ret = bus_add_driver(drv); // 驱动注册到总线
ret = driver_add_groups(drv, drv->groups); // 驱动kobj分配到驱动属性组
kobject_uevent(&drv->p->kobj, KOBJ_ADD); // 通过发送uevent通知用户空间
deferred_probe_extend_timeout(); // 取消延迟的工作(如果存在),延迟后将工作任务放入全局工作队列
// deferred_probe_timeout_work
return ret;
}
EXPORT_SYMBOL_GPL(driver_register);
bus_add_driver 驱动注册到总线
获取总线对象
分配驱动私有结构对象
初始化klist 设备结构
驱动私有结构的knode_bus 加入 bus私有结构的klist_drivers链表中
驱动程序遍历总线中的设备是否匹配,匹配则执行探测相关函数
驱动增加到模块
驱动创建sysfs属性文件(用户事件)
驱动kobj分配到总线的驱动属性组
驱动创建sysfs属性文件(unbind和bind)
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;
bus = bus_get(drv->bus); // 获取总线对象
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
priv = kzalloc(sizeof(*priv), GFP_KERNEL); // 分配驱动私有结构对象
klist_init(&priv->klist_devices, NULL, NULL); // 初始化klist 设备结构
priv->driver = drv; // 关联设备驱动结构对象
drv->p = priv; // 关联驱动私有结构对象
priv->kobj.kset = bus->p->drivers_kset; // 关联驱动列表(容器)
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name); // 私有结构对象的根kobj初始化
// driver_ktype 驱动动态注册的sysfs的ktype(用于释放对象,访问sysfs文件等等)
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); // 驱动私有结构的knode_bus 加入 bus私有结构的klist_drivers链表中
// 驱动结构与设备结构的创建过程(如结构的关系形式)大致相同
if (drv->bus->p->drivers_autoprobe) { // 自动探测
error = driver_attach(drv); // 驱动程序遍历总线中的设备是否匹配,匹配则执行探测相关函数
// 驱动检查id列表(动态和静态)是否与设备匹配,匹配的情况下,执行驱动探测设备及延迟处理(如果需要)
if (error)
goto out_del_list;
}
module_add_driver(drv->owner, drv); // 驱动增加到模块
error = driver_create_file(drv, &driver_attr_uevent); // 驱动创建sysfs属性文件(用户事件)
error = driver_add_groups(drv, bus->drv_groups); // 驱动kobj分配到总线的驱动属性组
if (!drv->suppress_bind_attrs) { // false
error = add_bind_files(drv); // 驱动创建sysfs属性文件(unbind和bind)
if (error) {
/* Ditto */
printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
__func__, drv->name);
}
}
return 0;
}
driver_attach 驱动程序遍历总线中的设备是否匹配,匹配则执行探测相关函数
驱动检查id列表(动态和静态)是否与设备匹配,匹配的情况下,执行驱动探测设备及延迟处理(如果需要)
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); // 遍历总线上的设备
// 驱动检查id列表(动态和静态)是否与设备匹配,匹配的情况下,执行驱动探测设备及延迟处理(如果需要)
}
EXPORT_SYMBOL_GPL(driver_attach);
__driver_attach
bus_for_each_dev
__driver_attach 驱动检查id列表(动态和静态)是否与设备匹配,匹配的情况下,执行驱动探测设备及延迟处理(如果需要)
检查驱动关联id列表(动态和静态)是否与设备匹配,匹配则返回1
默认情况下,驱动名称是否匹配保存异步探测驱动程序的名称,或模块异步探测驱动有效
执行驱动探测设备及延迟处理(如果需要)
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;
bool async = false;
int ret;
/*
* 锁定设备并尝试绑定到它
* 我们在此处删除错误,并始终返回0
* 因为我们需要继续尝试绑定到设备
* 如果某些驱动程序不支持该设备,则会返回错误
*
* 如果出现错误,driver_be_device()将发出警告
*/
ret = driver_match_device(drv, dev); // 检查驱动关联id列表(动态和静态)是否与设备匹配,匹配则返回1
// 如果总线实现了match函数,执行match
// pci总线实现函数 pci_bus_match 判断一个PCI设备结构是否具有匹配的PCI设备id结构
...
else if (ret == -EPROBE_DEFER) { // pci不支持此选项
dev_dbg(dev, "Device match requests probe deferral\n");
dev->can_match = true;
driver_deferred_probe_add(dev); // 延迟匹配
// 设备私有结构的deferred_probe,放入deferred_probe_pending_list链表
// driver_deferred_probe_trigger 启动重新探测延迟设备函数时
// 唤醒工作队列,为deferred_probe_pending_list链表中的每一个deferred_probe关联的设备执行探测函数
/*
* 驱动程序无法与设备匹配,但可能与总线上的其他设备匹配
*/
return 0;
}
...
if (driver_allows_async_probing(drv)) { // 默认情况下,驱动名称是否匹配保存异步探测驱动程序的名称,或模块异步探测驱动有效
// #define ASYNC_DRV_NAMES_MAX_LEN 256
// static char async_probe_drv_names[ASYNC_DRV_NAMES_MAX_LEN]; 内核命令行保存异步探测驱动程序的名称
// static bool async_probe_default; // 异步探测驱动程序是否启动
// module->async_probe_requested (drv->owner <-> module) 模块异步探测驱动
/*
* 我们将异步探测设备,而不是同步探测设备,以允许更多的并行性
*
* 我们在这里只使用设备锁,以确保dev->driver和async_driver字段受到保护
*/
dev_dbg(dev, "probing driver %s asynchronously\n", drv->name);
device_lock(dev);
if (!dev->driver && !dev->p->async_driver) {
get_device(dev);
dev->p->async_driver = drv; // 设备私有结构的异步驱动成员关联驱动
async = true;
}
device_unlock(dev);
if (async)
async_schedule_dev(__driver_attach_async_helper, dev); // 异步执行__driver_attach_async_helper函数
// 驱动探测设备及延迟处理(如果需要)
return 0;
}
__device_driver_lock(dev, dev->parent); // 设备加锁
// 设备父级存在,父级加锁,否则设备加锁
driver_probe_device(drv, dev); // 驱动探测设备及延迟处理(如果需要)
__device_driver_unlock(dev, dev->parent); // 设备释放锁
return 0;
}
bus_for_each_dev 遍历总线上的设备
int bus_for_each_dev(struct bus_type *bus, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device *dev;
int error = 0;
if (!bus || !bus->p)
return -EINVAL;
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL)); // 初始化klist 设备迭代器结构
while (!error && (dev = next_device(&i)))
error = fn(dev, data); // 如果当前设备节点存在,执行__driver_attach函数
klist_iter_exit(&i);
return error;
}
EXPORT_SYMBOL_GPL(bus_for_each_dev);
__driver_attach_async_helper 驱动探测设备及延迟处理(如果需要)
static void __driver_attach_async_helper(void *_dev, async_cookie_t cookie)
{
struct device *dev = _dev;
struct device_driver *drv;
int ret;
__device_driver_lock(dev, dev->parent); // 设备加锁
// 设备父级存在,父级加锁,否则设备加锁
// dev->mutex
drv = dev->p->async_driver;
dev->p->async_driver = NULL;
ret = driver_probe_device(drv, dev); // 驱动探测设备及延迟处理(如果需要)
__device_driver_unlock(dev, dev->parent); // 设备释放锁
dev_dbg(dev, "driver %s async attach completed: %d\n", drv->name, ret);
put_device(dev); // 减少设备引用计数
}
driver_probe_device 驱动探测设备及延迟处理(如果需要)
驱动探测设备
如果返回EPROBE_DEFER相关状态,驱动请求探测重试
放入延迟探测列表
探测过程中发生了触发器,启动重新探测延迟的设备
唤醒probe_waitqueue等待队列
static int driver_probe_device(struct device_driver *drv, struct device *dev)
{
int trigger_count = atomic_read(&deferred_trigger_count); // 读取原子计数
// 原子 deferred_trigger_count 用于确定在探测驱动程序过程中是否发生了成功的触发
// 如果在探测过程中触发计数发生变化,则应再次触发延迟处理
int ret;
atomic_inc(&probe_count); // 探测计数自增
ret = __driver_probe_device(drv, dev); // 驱动探测设备
if (ret == -EPROBE_DEFER || ret == EPROBE_DEFER) {
#define EPROBE_DEFER 517 /* 驱动请求探测重试 */
driver_deferred_probe_add(dev); // 放入延迟探测列表
/*
* 探测过程中是否发生了触发器?如果是,需要重新触发
*/
if (trigger_count != atomic_read(&deferred_trigger_count) &&
!defer_all_probes)
driver_deferred_probe_trigger(); // 启动重新探测延迟的设备
}
atomic_dec(&probe_count); // 探测计数自减
wake_up_all(&probe_waitqueue); // 唤醒probe_waitqueue等待队列
return ret;
}
__driver_probe_device 驱动探测设备
如果驱动允许匹配
恢复(唤醒)厂商设备并修改引用计数
刷新挂起的请求并等待完成
执行探测处理函数
为设备排队执行“空闲检查”
删除对厂商设备的引用
static int __driver_probe_device(struct device_driver *drv, struct device *dev)
{
int ret = 0;
...
dev->can_match = true; // 可以匹配
...
pm_runtime_get_suppliers(dev); // 恢复(唤醒)厂商设备并修改引用计数
// static DEFINE_MUTEX(device_links_lock); 设备链接 写相关的锁
// DEFINE_STATIC_SRCU(device_links_srcu); // 设备链接 读相关的锁
// SRCU 可休眠读拷贝更新(Sleepable Read-copy update)
if (dev->parent)
pm_runtime_get_sync(dev->parent); // 启动设备的使用计数器并恢复
pm_runtime_barrier(dev); // 刷新挂起的请求并等待完成
if (initcall_debug) // /sys/module/kernel/parameters/initcall_debug
ret = really_probe_debug(dev, drv); // 执行探测处理函数,加debug信息
else
ret = really_probe(dev, drv); // 探测处理函数
pm_request_idle(dev); // 为设备排队执行“空闲检查”
// 对一个工作项进行排队,以异步方式为设备运行相当于pm_runtime_idle()的函数
if (dev->parent)
pm_runtime_put(dev->parent); // 丢弃设备使用计数器,如果为0则排队“空闲检查”
// 减少设备的运行时PM使用计数器,如果它等于0,就像pm_request_idle()一样为设备排队一个工作项
pm_runtime_put_suppliers(dev); // 删除对厂商设备的引用
return ret;
}
really_probe 探测处理函数
检查是否存在厂商驱动程序
设备设置引脚相关内容
设置DMA配置(如果开启了CONFIG_OF,设备树相关)
驱动通知、链接,及创建sysfs属性文件
驱动探测
设备根kobj关联/分配到设备属性组
驱动探测已完成,更新引脚控制状态
驱动绑定设备
static int really_probe(struct device *dev, struct device_driver *drv)
{
bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE) &&
!drv->suppress_bind_attrs; // false
int ret, link_ret;
link_ret = device_links_check_suppliers(dev); // 检查是否存在厂商驱动程序
...
re_probe:
dev->driver = drv;
/* 如果使用pinctrl,请在探测之前立即绑定引脚 */
ret = pinctrl_bind_pins(dev); // 设备设置引脚相关
if (dev->bus->dma_configure) { // 设置DMA配置
ret = dev->bus->dma_configure(dev); // 函数更新PCI设备的DMA配置
// 使用相同的信息从主机桥的父节点的OF节点或ACPI节点(如果有)
if (ret)
goto pinctrl_bind_failed;
}
ret = driver_sysfs_add(dev); // 驱动通知、链接,及创建sysfs属性文件
if (dev->pm_domain && dev->pm_domain->activate) {
ret = dev->pm_domain->activate(dev); // 设备恢复
if (ret)
goto probe_failed;
}
ret = call_driver_probe(dev, drv); // 驱动探测
// 执行pci_device_probe函数
// 通过主桥设备对象找到pin值(引脚号)
// 计算出卡槽位置(槽号),然后通过槽号找到对应的中断号
// 写入到中断线(行)并关联到pci设备(由pci驱动使用)
// 最后在连接设备的cpu上执行驱动程序初始化,执行驱动的探测函数(用户注册的驱动)
ret = device_add_groups(dev, drv->dev_groups); // 设备根kobj关联/分配到设备属性组
// 获取kobj对象的sysfs所有权数据
// 创建kernfs_node节点及命名空间 (父级kn,如目录)
// 然后为属性组->属性列表中的属性分配kernfs_node节点及初始化(子级kn,如目录/文件)
// 包括关联kernfs_ops对象,将kernfs_node链接到同级rbtree
// 更新哈希值及时间戳,并激活这个节点(属性列表中的节点)
if (dev_has_sync_state(dev)) { // 如果设备驱动 或 总线的同步状态函数存在
ret = device_create_file(dev, &dev_attr_state_synced); // // 为设备创建sysfs属性文件
}
pinctrl_init_done(dev); // 驱动探测已完成,更新引脚控制状态
if (dev->pm_domain && dev->pm_domain->sync)
dev->pm_domain->sync(dev);
driver_bound(dev); // 驱动绑定设备
pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
goto done;
...
done:
return ret;
}
pinctrl_bind_pins 设备设置引脚相关
如果设备节点与父级设备共享引脚,不执行以下过程
分配设备的引脚状态容器对象
创建两级引脚控制对象指针,二级指针关联到设备
查找/分配默认的引脚控制状态结构
查找/分配初始的引脚控制状态结构
选择/激活/编程一个引脚控制状态到硬件
查找/分配睡眠引脚控制状态结构
查找/分配空闲引脚控制状态结构
int pinctrl_bind_pins(struct device *dev)
{
int ret;
if (dev->of_node_reused) // 如果设备(树)节点与上级设备共享
return 0;
dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL); // 分配设备的引脚状态容器对象
// 分配设备资源对象,设备资源节点的列表(链表,node->entry)放入dev->devres_head链表
dev->pins->p = devm_pinctrl_get(dev); // 创建两级引脚控制对象指针,二级指针关联到设备
// 一级指针引脚控制放入pinctrl_list(引脚控制链表)
// 二级指针引脚控制作为设备资源对象的data成员 关联到设备 (node->entry 放入 dev->devres_head链表)
dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,
PINCTRL_STATE_DEFAULT); // 查找/分配默认的引脚控制状态结构
// #define PINCTRL_STATE_DEFAULT "default"
// 初始化settings链表
// node链表放入引脚控制的状态链表(p->states)
dev->pins->init_state = pinctrl_lookup_state(dev->pins->p,
PINCTRL_STATE_INIT); // 查找/分配初始的引脚控制状态结构
// #define PINCTRL_STATE_INIT "init"
...
ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state); // 选择/激活/编程一个引脚控制状态到硬件
#ifdef CONFIG_PM
/*
* 如果启用了电源管理,我们还将查找可选的睡眠和空闲引脚状态
* 语义如中所定义
*/
dev->pins->sleep_state = pinctrl_lookup_state(dev->pins->p,
PINCTRL_STATE_SLEEP); // 查找/分配睡眠引脚控制状态结构
// #define PINCTRL_STATE_SLEEP "sleep"
dev->pins->idle_state = pinctrl_lookup_state(dev->pins->p,
PINCTRL_STATE_IDLE); // 查找/分配空闲引脚控制状态结构
// #define PINCTRL_STATE_IDLE "idle"
#endif
return 0;
...
}
create_pinctrl 创建引脚控制对象
static struct pinctrl *create_pinctrl(struct device *dev,
struct pinctrl_dev *pctldev)
{
struct pinctrl *p;
const char *devname;
struct pinctrl_maps *maps_node;
int i;
const struct pinctrl_map *map;
int ret;
/*
* 为每个映射创建状态cookie持有者结构pinctrl
* 这是消费者在使用pinctrl_get()请求pin控制句柄时会得到的
*/
p = kzalloc(sizeof(*p), GFP_KERNEL); // 分配引脚控制对象
p->dev = dev; // 关联设备
INIT_LIST_HEAD(&p->states); // 初始化状态链表
INIT_LIST_HEAD(&p->dt_maps); // 初始化设备树链表(部分架构不支持设备树概念,此概念相关结构的部分成员不使用)
ret = pinctrl_dt_to_map(p, pctldev); // 直接返回0
// x86_64默认没有启动 CONFIG_OF 选项,不使用设备树相关内容
devname = dev_name(dev); // 设备名称
...
pinctrl_maps这部分跳过
...
kref_init(&p->users); // 初始化引用计数器
// 专门用于引用计数的atomic-t的变体
/* 将引脚控制添加到全局列表 */
mutex_lock(&pinctrl_list_mutex);
list_add_tail(&p->node, &pinctrl_list); // 引脚控制放入pinctrl_list(引脚控制链表)
mutex_unlock(&pinctrl_list_mutex);
return p;
}
driver_sysfs_add 驱动通知、链接,及创建sysfs属性文件
执行通知链函数,驱动即将被绑定
驱动私有结构 链接到 设备
设备 链接到 驱动私有结构,链接名称"driver"
为设备创建sysfs属性文件
static int driver_sysfs_add(struct device *dev)
{
int ret;
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_BIND_DRIVER, dev); // 执行通知链(注册的)函数
// #define BUS_NOTIFY_BIND_DRIVER 0x00000004 /* 驱动即将被绑定 */
ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
kobject_name(&dev->kobj)); // 在两个对象之间创建符号链接,驱动私有结构 链接到 设备
ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
"driver"); // 设备 链接到 驱动私有结构,链接名称"driver"
ret = device_create_file(dev, &dev_attr_coredump); // 为设备创建sysfs属性文件
if (!ret)
return 0;
}
driver_bound 驱动绑定设备
设备私有结构的knode_driver 放入 设备驱动私有结构的klist_devices
设备分为延迟或同步两种状态类型,分别放入不同的列表
检查设备电源函数是否可以使用
确保设备不再在一个延迟列表中,并开始重新尝试所有挂起的设备
执行通知链(注册的)函数,驱动程序绑定到设备
用户事件通知(绑定通知)
static void driver_bound(struct device *dev)
{
...
klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
// 设备私有结构的knode_driver 放入 设备驱动私有结构的klist_devices
device_links_driver_bound(dev); // 设备分为延迟或同步两种状态类型,分别放入不同的列表
device_pm_check_callbacks(dev); // 检查设备电源函数是否可以使用
/*
* 确保设备不再在一个延迟列表中,并开始重新尝试所有挂起的设备
* /
driver_deferred_probe_del(dev); // 移除延迟列表
driver_deferred_probe_trigger(); // 启动重新探测延迟的设备
// *该函数将所有设备从挂起列表移动到活动列表
// 并调度延迟探测工作队列来处理它们
// 它应该在驱动程序成功绑定到设备时调用
// queue_work(system_unbound_wq, &deferred_probe_work);
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_BOUND_DRIVER, dev); // // 执行通知链(注册的)函数
// #define BUS_NOTIFY_BOUND_DRIVER 0x00000005 /* 驱动程序绑定到设备 */
kobject_uevent(&dev->kobj, KOBJ_BIND); // 用户事件通知
// 绑定通知
}
device_links_driver_bound 设备分为延迟或同步两种状态类型,分别放入不同的列表
void device_links_driver_bound(struct device *dev)
{
struct device_link *link, *ln;
LIST_HEAD(sync_list); // 定义、初始化sync_list链表对象
/*
* 如果一个设备绑定成功,那么它应该已经创建了它需要的所有设备链接
* 或者根据需要创建了新的设备链接
* 因此,fw_devlink不再需要创建到设备的任何厂商的设备链接
*
* 另外,如果这个绑定设备的子固件节点到现在还没有被添加为设备
* 那么假定它永远不会被添加,并确保其他设备不会通过等待这样的子设备无限期地延迟探测
*/
if (dev->fwnode && dev->fwnode->dev == dev) {
struct fwnode_handle *child;
fwnode_links_purge_suppliers(dev->fwnode); // 删除fwnode_handle的所有厂商链接
fwnode_for_each_available_child_node(dev->fwnode, child)
fw_devlink_purge_absent_suppliers(child);
}
device_remove_file(dev, &dev_attr_waiting_for_supplier); // 移除sysfs属性文件
...
if (link->flags & DL_FLAG_AUTOPROBE_CONSUMER)
driver_deferred_probe_add(link->consumer); // 放入延迟探测列表
// deferred_probe -> deferred_probe_pending_list
if (defer_sync_state_count)
__device_links_supplier_defer_sync(dev); // 设备放入延迟探测列表(deferred_sync)
else
__device_links_queue_sync_state(dev, &sync_list); // 设备放入同步状态列表
...
device_link_drop_managed(link); // 移除device_link相关的链表节点等
...
dev->links.status = DL_DEV_DRIVER_BOUND;
// DL_DEV_DRIVER_BOUND: 驱动已绑定到设备
...
device_links_flush_sync_list(&sync_list, dev); // 对设备列表调用sync_state函数
// 在已排队等待的所有设备上调用
}
module_add_driver 驱动增加到模块
void module_add_driver(struct module *mod, struct device_driver *drv)
{
char *driver_name;
int no_warn;
struct module_kobject *mk = NULL;
if (mod) // 指定了THIS_MODULE,并且编译选项为m或手动编译驱动,在编译时会生成__this_module结构对象
mk = &mod->mkobj;
else if (drv->mod_name) { // 编译选项为y时
struct kobject *mkobj;
/* 查找中的内置模块条目 /sys/modules */
mkobj = kset_find_obj(module_kset, drv->mod_name);
if (mkobj) {
mk = container_of(mkobj, struct module_kobject, kobj);
/* 记住我们的模块结构 */
drv->p->mkobj = mk;
/* kset_find_obj took a reference */
kobject_put(mkobj);
}
}
/* 不要检查返回代码;这些调用是幂等的 */
no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module");
// drv->p->kobj 链接到 mk->kobj "module"
driver_name = make_driver_name(drv);
if (driver_name) {
module_create_drivers_dir(mk);
no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj,
driver_name);
// mk->drivers_dir 链接到 drv->p->kobj 驱动名称
kfree(driver_name);
}
}
__this_module 编译选项为m或手动编译驱动,在编译时会生成__this_module结构对象
__visible struct module __this_module
__section(".gnu.linkonce.this_module") = {
.name = KBUILD_MODNAME,
.init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
.exit = cleanup_module,
#endif
.arch = MODULE_ARCH_INIT,
};