【C语言】linux内核pci_iomap

一、pci_iomap

/** pci_iomap 是一个用于映射 PCI 设备的 BAR(Base Address Register,基地址寄存器)的函数。* 此函数返回指向内存映射 IO 的指针,用于直接访问 PCI 设备的内存或 I/O 空间。* * 参数:* dev - 指向pci_dev结构的指针,表示PCI设备。* bar - 表示要映射的基地址寄存器的索引(0-5)。* maxlen - 要映射的最大长度;如果为0,则映射整个BAR空间。* * 返回值:* 成功时,函数返回指向映射区域的指针。* 如果映射失败,返回NULL。** 注意: 当不再需要访问映射的内存时,应调用pci_iounmap来释放映射的资源。*/
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
{return pci_iomap_range(dev, bar, 0, maxlen);
}
EXPORT_SYMBOL(pci_iomap); // 将 pci_iomap 函数导出,使得其它模块也能够调用该函数

这个函数 pci_iomap 是一个辅助函数,实际上它调用了 pci_iomap_range 函数,但是将 offset 设置为0,目的是简化对整个BAR的映射,而不是基于某个特定的起始偏移量。`pci_iomap` 在许多PCI驱动程序中被用来初始化设备操作所需的地址映射。

函数定义:lib\pci_iomap.c

二、pci_iomap_range

/*** pci_iomap_range - 为PCI BAR创建一个虚拟映射* @dev: 拥有BAR的PCI设备* @bar: BAR编号* @offset: 从BAR中给定的偏移量开始映射内存* @maxlen: 要映射的最大内存长度** 使用该函数可以获得指向设备BAR的__iomem地址。* 可以使用ioread*()和iowrite*()来进行访问。这些函数会隐藏* 是MMIO还是PIO地址空间的细节,并且会按照预期的方式正确地工作。** @maxlen 指定了要映射的最大长度。如果您想访问从偏移量到结束的完整BAR,* 在这里传递%0。*/
void __iomem *pci_iomap_range(struct pci_dev *dev,int bar,unsigned long offset,unsigned long maxlen)
{//获取BAR资源的起始地址resource_size_t start = pci_resource_start(dev, bar);//获取BAR资源的总长度resource_size_t len = pci_resource_len(dev, bar);//获取BAR资源的标志unsigned long flags = pci_resource_flags(dev, bar);//如果资源长度不足或起始地址为0,则返回NULLif (len <= offset || !start)return NULL;//减去偏移量,获得新的长度len -= offset;//根据偏移量更新起始地址start += offset;//如果有指定最大长度,并且新的长度大于它,则使用最大长度if (maxlen && len > maxlen)len = maxlen;//如果是I/O资源,使用__pci_ioport_map进行映射if (flags & IORESOURCE_IO)return __pci_ioport_map(dev, start, len);//如果是内存资源,使用ioremap进行映射if (flags & IORESOURCE_MEM)return ioremap(start, len);//如果不是I/O资源也不是内存资源,返回NULLreturn NULL;
}
//导出pci_iomap_range符号,使其在内核其他模块中可用
EXPORT_SYMBOL(pci_iomap_range);

上述代码是Linux内核中的一个函数注释,它是用于将PCI设备的某个BAR(基址地址寄存器)区域映射到内核虚拟地址空间,以便于内核或驱动程序可以直接通过这个虚拟地址对硬件设备进行访问。这个机制是PCI驱动程序常用的方法之一。

函数定义:lib\pci_iomap.c

三、pci_iomap和pci_iomap_range

/*** pci_iomap_range - 为PCI设备的BAR创建虚拟映射* @dev: 拥有BAR的PCI设备* @bar: BAR编号* @offset: 从BAR的给定偏移量处开始映射内存* @maxlen: 需要映射的内存的最大长度** 使用此函数可以获取到指向设备BAR的__iomem地址。* 您可以使用ioread*() 和 iowrite*() 来访问其地址。* 这些函数会隐藏这是一个MMIO地址还是PIO地址空间的细节,* 并以您期望的正确方式进行操作。** @maxlen 指定映射的最大长度。如果您想要从偏移量到末尾访问整个BAR,* 请在这里传递%0(即传递0表示映射整个BAR的长度)。*/
void __iomem *pci_iomap_range(struct pci_dev *dev,int bar,unsigned long offset,unsigned long maxlen)
{// ... 实现细节略 ...
}
EXPORT_SYMBOL(pci_iomap_range);/*** pci_iomap - 为PCI设备的BAR创建虚拟映射* @dev: 拥有BAR的PCI设备* @bar: BAR编号* @maxlen: 需要映射的内存的长度** 使用此函数可以获取到指向设备BAR的__iomem地址。* 您可以使用ioread*() 和 iowrite*() 来访问这个地址。* 这些函数会隐藏这是一个MMIO地址还是PIO地址空间的细节,* 并以您期望的正确方式进行操作。** @maxlen 指定映射的最大长度。如果您想要访问整个BAR而不首先检查其长度,* 请在这里传递%0(即传递0表示映射整个BAR的长度)。*/
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
{// ... 实现细节略 ...
}
EXPORT_SYMBOL(pci_iomap);

这两个函数都是用来建立PCI设备的BAR(Base Address Register,基址寄存器)到进程的虚拟地址空间的映射。通过这个映射,程序可以通过标准的I/O访问函数来读写设备的硬件寄存器。
pci_iomap_range允许指定一个起始偏移量和最大映射长度,可以用来映射BAR内部一段特定的内存区域。
pci_iomap是一个简化的版本,它默认从BAR的起始处映射整个区域,或者是指定长度的内存。(当maxlen为0时映射整个BAR)。
EXPORT_SYMBOL宏用于导出符号,使得这些函数可以在内核模块之间共享。 

ChatGPT

在Linux内核中,`pci_iomap`是一个用于将PCI设备的内存或I/O端口映射到内核虚拟地址空间的内核函数。这使得内核代码可以通过正常的指针操作来访问PCI设备的资源。
函数的原型通常如下所示:

void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen);

参数解释:
- dev:指向`pci_dev`结构的指针,它表示要映射的PCI设备。
- bar:要映射的PCI设备的Base Address Register (BAR) 索引,其值从0开始。
- maxlen:映射区域的最大长度。如果该值为0,则表示映射从BAR开始的整个区域。
返回值:
该函数返回一个`void __iomem *类型的指针,它指向请求的映射区域的起始地址,如果映射失败,则返回NULL`。
使用`pci_iomap`函数可以直接访问PCI设备的内存,这通常在设备驱动程序初始化时完成。例如,驱动程序会调用`pci_iomap`来获取指向设备寄存器的指针,之后就可以通过这个指针来读写寄存器。
在使用完毕映射的内存后,应该调用`pci_iounmap()`函数来解除映射。
例如:

#define MY_DEVICE_BAR 0struct pci_dev *pdev; // 假设已经通过某种方式获得
void __iomem *iomem;// 映射BAR 0
iomem = pci_iomap(pdev, MY_DEVICE_BAR, 0);
if (!iomem) {// 处理错误情况
}// 使用iomem指针访问PCI设备内存
writeb(value, iomem + offset); // 写入字节
// 或者
writel(value, iomem + offset); // 写入长字// 解除映射
pci_iounmap(pdev, iomem);

请记住,在写驱动程序时,应确保遵循操作系统的内存管理和设备操作准则,以确保系统稳定性和安全性。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ClickHouse初体验

1.clickHouse是啥&#xff1f; ClickHouse 是俄罗斯的 Yandex 于 2016 年开源的列式存储数据库(DBMS)&#xff0c;使用 C语言编写&#xff0c;主要用于在线分析处理查询(OLAP)&#xff0c;能够使用SQL查询实时生成分析数据报告 2.clickHouse的特点 2.1列式存储 对于列的聚合&…

SEO 的未来:GPT 和 AI 如何改变关键词研究

谷歌Gemini与百度文心一言&#xff1a;AI训练数据的较量 介绍 想象一下&#xff0c;有一个工具不仅可以理解错综复杂的关键字网络&#xff0c;还可以预测搜索引擎查询的变化趋势。 这就是生成式预训练 Transformer (GPT) 和其他人工智能技术发挥作用的地方&#xff0c;以我们从…

基于RK3588多can口多串口机器人全功能板

RK3588机器人控制器有五大技术优势 1. 内置多种功能强大的嵌入式硬件引擎&#xff0c;支持8K60fps 的 H.265 和 VP9 解码器、8K30fps 的 H.264 解码器和 4K60fps 的 AV1 解码器&#xff1b;支持 8K30fps 的 H.264 和H.265 编码器&#xff0c;高质量的 JPEG 编码器/解码器&…

二十 超级数据查看器 讲解稿 功能概述

二十 超级数据查看器 讲解稿 功能概述 ​ ​​点击此处 以新页面 打开B站 播放当前教学视频 点击访问app下载页面 豌豆荚 下载地址​ ​ 讲解稿 ​ 界面启动 ​ 导入 ​ 选excel文件 导入 ​ 原来的excel文件 ​ 导入进本地数据库sqlite ​ 导入成功 ​ 列…

Lilishop商城(windows)本地部署【docker版】

Lilishop商城&#xff08;windows&#xff09;本地部署【docker版】 部署官方文档&#xff1a;LILISHOP-开发者中心 https://gitee.com/beijing_hongye_huicheng/lilishop 本地安装docker https://docs.pickmall.cn/deploy/win/deploy.html 命令端页面 启动后docker界面 注…

C++ STL教程

C STL教程 文章目录 C STL教程1.1 std::vector1.1.1vector的定义1.1.2vector容器的初始化1.1.3vector容器内元素的访问和修改1.1.4vector中的常用函数 1.2 std::string1.2.1string的定义1.2.2string的初始化1.2.3string中元素的访问和修改1.2.4string中连接字符串1.2.5string中…

C++类模板详解

在学习类模板之前可以了解一下函数模板&#xff0c;可以参考我的另一篇文章C函数模板详解&#xff08;结合代码&#xff09;-CSDN博客 讲解的比较详细&#xff0c;有助于理解类模板。 目录 1、什么是类模板&#xff1f; 2、类模板与函数模板区别 3、类模板对象做函数参数 …

单调栈(C++)

单调栈,即栈中元素是单调递增的或是单调递减的,是一个比较好用的数据结构. 柱状图中最大的矩形 84. 柱状图中最大的矩形 - 力扣&#xff08;LeetCode&#xff09; 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。…

IRIS / Chronicles 数据库结构

对于我们用得最多的关系型数据库来说&#xff0c;首先有的是数据库名字&#xff0c;然后是表名字&#xff0c;然后就是字段名&#xff0c;随后就是一条一条的数据。 对于 IRIS 来说&#xff0c;因为是使用的层级数据库&#xff0c;所以上面的定义就不能完全的照搬了&#xff0…

Java 学习和实践笔记(49):用javabean和一维数组的方式来存储表格数据

还是存储下面这个表格的数据&#xff0c;但使用另一种方法来做。 用javabean和一维数组的方法来做&#xff0c;示例代码如下&#xff1a; /*先创建一个类&#xff0c;其实就是创建好一个只有各属性列的空表格*/ class Employees {private int id;private String name;private …

vue2高德地图选点

<template><el-dialog :title"!dataForm.id ? 新建 : isDetail ? 详情 : 编辑" :close-on-click-modal"false" :visible.sync"show" class"rv-dialog rv-dialog_center" lock-scroll width"74%" :before-close&q…

未能加载文件或程序集socutdata或它的某一个依赖项试图加载格式不正确的程序

未能加载文件或程序集socut data或它的某一个依赖项试图加载格式不正确的程序 Socut.Data.dll找不到类型或命名空间名称 把bin目录下面 的socut.data.dll删除就行了 C#报错未能加载文件或程序集socut data或它的某一个依赖项试图加载格式不正确的程序 "/"应用程序…