【C语言】linux内核pci_register_driver

一、注释

以下是对源代码中英文注释的中文翻译,可能会略去一些编程上的专有词汇(例如函数名、类型名等),以使翻译更易理解。

// drivers\pci\pci-driver.c
/**
 * __pci_register_driver - 注册一个新的PCI驱动
 * @drv: 需要注册的驱动结构体
 * @owner: 拥有该drv的模块
 * @mod_name: 模块的名称字符串
 *
 * 将驱动结构体添加到已注册驱动的列表中。
 * 注册失败时返回负值,否则返回0。
 * 如果没有发生错误,即使在注册期间没有设备被认领,
 * 驱动仍然会保持注册状态。
 */
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;

    // 初始化动态ID锁和列表
    spin_lock_init(&drv->dynids.lock);
    INIT_LIST_HEAD(&drv->dynids.list);

    /* 在核心层注册 */
    return driver_register(&drv->driver);
}
EXPORT_SYMBOL(__pci_register_driver);

// include\linux\pci.h
/* 支持可热插拔设备的正确探测 */
int __must_check __pci_register_driver(struct pci_driver *, struct module *,
                                       const char *mod_name);

/* pci_register_driver() 必须是一个宏,这样才能扩展 KBUILD_MODNAME */
#define pci_register_driver(driver)        \
    __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)


/**
 * module_pci_driver() - 用于注册PCI驱动的辅助宏
 * @__pci_driver: pci_driver结构体
 *
 * 这是一个辅助宏,用于PCI驱动,如果在模块的初始化/退出中没有特殊操作。
 * 这个宏可以简化很多代码。每个模块只能使用这个宏一次,且使用后会替代
 * module_init() 和 module_exit()。
 */
#define module_pci_driver(__pci_driver) \
    module_driver(__pci_driver, pci_register_driver, pci_unregister_driver)

/**
 * builtin_pci_driver() - 注册PCI驱动的辅助宏
 * @__pci_driver: pci_driver结构体
 *
 * 这是一个辅助宏,用于PCI驱动,如果在它们的初始化代码中没有特殊操作。
 * 这个宏可以简化很多代码。每个驱动只能使用这个宏一次,且使用后将替代
 * device_initcall(...)。
 */
#define builtin_pci_driver(__pci_driver) \
    builtin_driver(__pci_driver, pci_register_driver)

在源代码注释中,它描述了如何在Linux内核中注册一个PCI设备驱动。提供了一些宏来简化驱动注册和初始化过程。这些宏对于不需要复杂初始化和退出函数的标准PCI驱动来说是非常有用的,可以减少代码冗余。

二、讲解

这些代码片段主要来自于 Linux 内核源码,涉及到 PCI(Peripheral Component Interconnect)驱动程序的注册和管理。PCI 是一种连接计算机外围设备的总线标准。

第一段代码是 __pci_register_driver 函数的实现。这个函数用来注册一个新的 PCI 驱动程序。让我们逐行解释:

int __pci_register_driver(struct pci_driver *drv, struct module *owner, const char *mod_name)

这个函数接受3个参数:要注册的驱动程序结构体,驱动程序所属的模块以及模块的名称字符串。

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;

这部分代码初始化了 pci_driver 结构体的一些成员字段。这包括驱动程序的名称、它所属的总线类型(在这里是 PCI 总线)、它的拥有者(通常是加载它的模块)、模块名称以及属性组。

spin_lock_init(&drv->dynids.lock);
INIT_LIST_HEAD(&drv->dynids.list);

这两行代码初始化了用于动态设备 ID 管理的自旋锁和链表头。

return driver_register(&drv->driver);

最终调用了 driver_register 函数,该函数将 pci_driver 结构体添加到内核的驱动程序列表中。如果注册成功,返回0,否则返回负值错误码。

EXPORT_SYMBOL(__pci_register_driver);

这行代码导出上面定义的 __pci_register_driver 函数,使得其他内核模块可以调用它。

-----

第二段代码中 pci_register_driver 是一个宏定义,其作用是将驱动程序注册到PCI子系统。它封装了 __pci_register_driver 函数,将当前模块(`THIS_MODULE`)和模块名称(通过 KBUILD_MODNAME 宏定义)作为参数传递。

#define pci_register_driver(driver) \
    __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)

-----

第三段代码包含了两个辅助宏:`module_pci_driver` 和 builtin_pci_driver。这些宏简化了驱动程序的初始化和退出代码。

#define module_pci_driver(__pci_driver) \
  module_driver(__pci_driver, pci_register_driver, pci_unregister_driver)

module_pci_driver 宏定义用于注册和注销驱动程序,它用来替代 module_init 和 module_exit 宏。这使得不需要显式定义初始化和清理函数的 PCI 驱动程序可以更简洁地编写。

#define builtin_pci_driver(__pci_driver) \
  builtin_driver(__pci_driver, pci_register_driver)

builtin_pci_driver 宏是类似的,但是用于内建驱动程序的注册。调用它会替代典型的 device_initcall 宏。这主要用于那些编译到内核本身,而不是作为模块加载的驱动程序。

总结而言,这些代码片段涵盖了 Linux 内核中 PCI 驱动程序注册的不同方面,从注册具体的驱动到提供宏简化驱动程序模块的编写。这些机制都是 Linux 设备驱动框架的一部分,用于确保各种设备的驱动程序可以被正确识别、加载和管理。

通义灵码

在Linux内核中,pci_register_driver() 是一个用于注册PCI(Peripheral Component Interconnect)设备驱动程序的关键函数。它允许驱动程序声明自己能够支持特定类型的PCI设备,以便当系统检测到匹配的PCI设备插入时,能够自动加载并初始化相应的驱动。

#include <linux/pci.h>

static struct pci_driver my_pci_driver = {
    .name     = "my_pci_drv",
    .id_table = my_pci_ids,
    .probe    = my_pci_probe,
    .remove   = my_pci_remove,
    /* 其他可能的回调函数 */
};

static int __init my_pci_init(void)
{
    return pci_register_driver(&my_pci_driver);
}

static void __exit my_pci_exit(void)
{
    pci_unregister_driver(&my_pci_driver);
}

module_init(my_pci_init);
module_exit(my_pci_exit);

上面的示例展示了如何使用 pci_register_driver() 函数:

  • my_pci_driver 是一个 struct pci_driver 类型的变量,其中包含了驱动程序的相关信息:

    • .name 是驱动程序的名字,用于标识和调试。
    • .id_table 是一个包含一组PCI设备ID列表的表,每个设备ID定义了驱动程序所支持的设备范围。
    • .probe 是一个回调函数,当发现新的PCI设备并且其ID与.id_table中定义的ID相匹配时,系统将调用这个函数来初始化设备。
    • .remove 是一个在设备被移除或驱动程序卸载时调用的清理函数。
  • my_pci_init() 是模块的初始化函数,在模块被加载时调用,它调用 pci_register_driver() 注册驱动程序。

  • my_pci_exit() 是模块的退出函数,在模块被卸载时调用,它调用 pci_unregister_driver() 取消注册驱动程序。

通过这样的机制,Linux内核能够灵活管理各种PCI设备的动态插拔,实现了设备驱动的即插即用(Plug-and-Play)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/515593.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【QT入门】 无边框窗口设计综合运用之自定义标题栏带圆角阴影的窗口

往期回顾&#xff1a; 【QT入门】 自定义标题栏界面qss美化按钮功能实现-CSDN博客 【QT入门】 无边框窗口设计之实现窗口阴影-CSDN博客 【QT入门】 无边框窗口设计之实现圆角窗口-CSDN博客 【QT入门】 无边框窗口设计综合运用之自定义标题栏带圆角阴影的窗口 一、最终效果 二、…

数据结构进阶篇 之 【交换排序】(冒泡排序,快速排序递归、非递归实现)

当你觉的自己不行时&#xff0c;你就走到斑马线上&#xff0c;这样你就会成为一个行人 一、交换排序 1.冒泡排序 BubbleSort 1.1 基本思想 1.2 实现原理 1.3 代码实现 1.4 冒泡排序的特性总结 2.快速排序 QuickSort 2.1 基本思想 2.2 递归实现 2.2.1 hoare版 2.2.2 …

开发环境->生产环境

1、数据迁移 不涉及docker # 以数据库用户导出数据 mysqldump -h 192.168.1.168 -P 3307 -u abragent -pabragebb17 abragent > abragent.sql# 以root用户导出数据 mysqldump -h 192.168.1.168 -P 3307 -u root -p8d3Ba1b abragent > abragent.sql 涉及docker …

java自动化学习-IntelliJ IDEA新建项目

1、新建项目 2、新建类&#xff0c;右键”src” > “new” >”Java Class” 3、重命名类名

【史上最细教程】项目本地切换Nexus私服步骤

文章目录 1.上传所有jar/pom到私服仓库方式1&#xff1a;Nexus手动上传方式2&#xff1a;mvn deploy命令上传 2.替换项目中所有pom.xml上传下载地址为私服仓库3.替换本地maven setting.xml配置文件4.下载上传验证操作下载jar出现的问题mvn deploy上传jarmvn deploy上传执行脚本…

R语言实现蒙特卡洛模拟算法

&#x1f349;CSDN小墨&晓末:https://blog.csdn.net/jd1813346972 个人介绍: 研一&#xff5c;统计学&#xff5c;干货分享          擅长Python、Matlab、R等主流编程软件          累计十余项国家级比赛奖项&#xff0c;参与研究经费10w、40w级横向 文…

java 数据结构 Map和Set

目录 搜索树 操作-查找 操作-插入 操作-删除&#xff08;难点&#xff09; Map Map 的常用方法 Set 哈希表 哈希函数 哈希冲突 冲突-避免-负载因子调节&#xff08;重点掌握&#xff09; 冲突-解决 冲突-解决-开散列/哈希桶(重点掌握) 实现HashBuck类 put方法 …

C++实现 “你被骗了” 自动拦截,反诈神器

“Never Gonna Give You Up” &#xff0c; 已经是历经十五年的名梗了&#xff0c;点开这个视频&#xff0c;就说明 你被骗了。 无论是自己点进了一些奇奇怪怪的链接&#xff0c;还是被自动跳转&#xff0c;你都不希望 展开 0x01 原理&规则 【本程序B站视频链接】快去B站…

layui框架实战案例(26):layui-carousel轮播组件添加多个Echarts图标的效果

在Layui中&#xff0c;使用layui-carousel轮播组件嵌套Echarts图表来实现多个图表的展示。 css层叠样式表 调整轮播图背景色为白色&#xff1b;调整当个Echarts图表显示loading…状态&#xff1b;同一个DIV轮播项目添加多个Echarts的 .layui-carousel {background-color: #f…

【图论】有向无环图中一个节点的所有祖先 - 邻接表(DFS)

文章目录 题目&#xff1a;有向无环图中一个节点的所有祖先题目描述代码与解题思路 题目&#xff1a;有向无环图中一个节点的所有祖先 2192. 有向无环图中一个节点的所有祖先 题目描述 代码与解题思路 func getAncestors(n int, edges [][]int) [][]int {g : make([][]int, …

C#清空窗体的背景图片

目录 一、涉及到的知识点 1.设置窗体的背景图 2.加载窗体背景图 3.清空窗体的背景图 二、 示例 一、涉及到的知识点 1.设置窗体的背景图 详见本文作者的其他文章&#xff1a;C#手动改变自制窗体的大小-CSDN博客 https://wenchm.blog.csdn.net/article/details/137027140…

链路追踪原理

分布式系统为什么需要链路追踪&#xff1f; 随着互联网业务快速扩展&#xff0c;软件架构也日益变得复杂&#xff0c;为了适应海量用户高并发请求&#xff0c;系统中越来越多的组件开始走向分布式化&#xff0c;如单体架构拆分为微服务、服务内缓存变为分布式缓存、服务组件通…

IDEA2023.1.1中文插件

1.启动IDEA 选中Customize 2.选择All settings 3.选中Plugins,再搜索栏里输入Chinese,找到 "Chinese (Simplified) Language"插件&#xff0c;点击 Install 进行安装。 4. 安装完成后&#xff0c;重启IntelliJ IDEA&#xff0c;即可看到界面语言已经变为中文。

HashMap为啥线程不安全?

1. HashMap1.7在多线程并发下扩容时&#xff0c;头插法会出现环。 /*** Rehashes the contents of this map into a new array with a* larger capacity. This method is called automatically when the* number of keys in this map reaches its threshold.** If current cap…

回溯算法|491.递增子序列

力扣题目链接 class Solution { private:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& nums, int startIndex) {if (path.size() > 1) {result.push_back(path);// 注意这里不要加return&#xff0c;要取树上…

[计算机知识] TCP/IP网络模型、MySQL的结构

TCP/IP网络模型 应用层 给用户提供应用功能&#xff0c;如HTTP, DNS 应用层处于用户态&#xff0c;传输层及以下处于内核态 传输层 给应用层提供网络支持&#xff0c;如TCP, UDP TCP提供稳定、面向连接的网络传输协议 应用层的数据可能会太大&#xff0c;就需要进行拆分…

【GAMES101】Lecture08 09 Shading 3 (Texture Mapping cont.) 纹理映射 续集

目录 0 引言1 如何在三角形内进行插值&#xff1a;重心坐标1.1 为什么要在三角形内插值1.2 重心坐标1.3 使用重心坐标做三角形内颜色插值 2 应用纹理2.1 简单的纹理映射&#xff1a;漫反射2.2 问题&#xff1a;纹理放大&#xff08;采用插值解决&#xff09;2.2 点查询和范围查…

Qt主窗口 之:停靠/悬浮窗口(QDockWidget)

一、QDockWidget概述 QDockWidget 是 Qt 中的一个窗口部件&#xff0c;用于创建可停靠的窗口&#xff0c;通常用于构建多文档接口&#xff08;MDI&#xff09;或可定制的用户界面。QDockWidget 允许用户将窗口停靠在应用程序的主窗口周围&#xff0c;或将其拖动到独立的浮动窗…

STM32

GPIO通用输入输出口 GPIO:8种输入输出模式 浮空输入可读取引脚电平&#xff0c;若引脚悬空&#xff0c;电平不确定上拉输入可读取引脚电平&#xff0c;内部接上拉电阻&#xff0c;悬空时默认为高电平下拉输入可读取引脚电平&#xff0c;内部接下拉电阻&#xff0c;悬空时默认…

视频编辑的瑞士军刀,MoviePy库的详解与应用示例

左手编程&#xff0c;右手年华。大家好&#xff0c;我是一点&#xff0c;关注我&#xff0c;带你走入编程的世界。 公众号&#xff1a;一点sir&#xff0c;关注领取python编程资料 在数字媒体的时代&#xff0c;视频内容的创作和编辑变得越来越重要。无论是社交媒体上的短视频&…