<背景>

PCI设备有许多地址配置的寄存器,初始化时这寄存器来配置设备的总线地址,配置好后CPU就可以访问该设备的各项资源了。(提炼:配置总线地址)
 
<配置寄存器>
 
(1)256字节的PCI配置空间分为64字节的头标区和192字节的设备相关区两部分。头标区的各个寄存器用来唯一地识别设备;设备相关区则保存一些与设备相关的数据。
(2)配置空间的头标区又分为两部分:前16个字节的定义在各种类型的PCI设备中都是一样的;剩余的字节随设备类型不同而有所不同。位于偏移地址0EH处的头标类型字段规定了头标区的布局结构。目前,规范定义了三种头标类型。
                                 
a:设备的识别
(1)  供应商代码:该寄存器用于识别PCI设备的制造商,具体代码由PCI SIG(http://www.pcisig.com)分配。0FFFFH是无效的供应商代码。
(2)       设备代码。该寄存器用来标识某供应商生产的具体设备,代码由各供应商定义。供应商代码和设备代码,读者可以到网站http://www.pcidatabase.com/查阅。
(3)       版本号。该寄存器用来定义指定设备的版本信息。
(4)       头标类型。该字段的第7位为“1”标识该设备是多功能设备,为“0”标识为单功能设备;该字段的0~6位就是上文表中所述的头标类型。
(5)       设备分类代码。用来标识设备的总体功能和特定的寄存器级编程接口。
上面5个字段均为只读类型,所有的PCI设备都必须实现其功能。
b:设备控制和设备状态
(1)       命令寄存器为一个设备发出和响应PCI总线命令提供粗略的控制。图4就是命令寄存器格式。
 
位0(I/O空间控制):控制对I/O空间访问的响应。该位为0时,禁止设备响应对I/O空间的访问;该位为1时,允许设备响应I/O空间的访问。缺省设置为0。
位1(存储器空间控制):控制一个设备对存储器空间访问的响应。该位为0时,禁止响应;该位为1时,允许设备响应对存储器空间的访问。缺省设置为0。
 
状态寄存器用来记录PCI总线有关的状态信息。
c:基址寄存器
PCI设备中,除了配置空间外,还有两个物理空间:内存空间和I/O空间。为了访问这两个地址空间,就必须使用基址寄存器。头标类型0中涉及3种基址寄存器:内存空间基址寄存器、I/O空间基址寄存器和扩展ROM基址寄存器。
d:其他寄存器
其他寄存器包括一些本文不涉及到的寄存器,如中断引脚、中断线等等。 
<PCI配置空间的访问>
    a:PCI规范使用从0CF8H~0CFFH 这8个I/O地址来访问所有设备的PCI配置空间。这8个字节实际上构成了两个32位寄存器:0CF8H寄存器叫做“配置地址寄存器”;0CFCH叫做“配置数据寄存器”。当要访问配置空间的寄存器时,先向地址寄存器写上目标地址,然后就可以从数据寄存器中读写数据了。
        PCI配置空间对应于一个PCI逻辑设备,所以要访问一个配置空间的某个寄存器,必须要指定:PCI总线号、PCI设备号、PCI设备功能号和寄存器号。配置地址寄存器的格式如下:
                     
       第0、1位上的“0”是用来要求你只能按双字(4字节)来读写配置空间寄存器。第31位“使能位”用来决定是否允许访问配置空间:为“1”时表示可以访问;为“0”时表示不可以访问。
        从上面的配置地址寄存器的格式我们可以看出:总线号从0~255、设备号从0~31、功能号从0~7。根据配置空间的第0个寄存器是否返回0FFFFH值来判断是否存在该PCI设备(这里可以看出PCI为什支持32个设备)
 
<PCI驱动开发概总>
对于驱动开发人员来说,pci具有如下吸引人的优势:
a:设备自动配置系统,与旧的ISA驱动程序不一样,pci驱动不需要实现复杂的检测逻辑。
b:系统启动时,BIOS(如果是嵌入式系统内核本身会完成该任务)会遍历pci总线并分配资源(比如中断优先级,I/O基地址) 
c: 设备去驱动程序会查询叫做"PCI配置空间"的内存来找到资源分配情况
d:PCI设备总共具有256B的配置空间内存。配置空间 顶部64B空间的含义是标准的,所有设备的配置在这段区域都是相似的。该空间被分成状态,I/O基地址,中断线。
 
<访问PCI>
a:内核函数
pci_read_config_[byte|word|dword](struct pci_dev *pdev,int offset,int *value)
pci_write_config_[byte|word|dword](struct pci_dev *pdev,int offset,int *value)
形参分析:
pdev:指向PCI设备的结构体
offset:配置空间的偏移地址
value:需要写入或读出数据的存放位置
举例:
unsigned char irq;
pci_read_config_byte(pdev,PCI_INTERRUPT_LINE,&irq);
注意:在配置空间中的中断号的偏移是60,这为什么不使用60,是因为在Linux内核中/include/linux/pci_regs.h进行了定义。
 
<I/O和内存>
I/O访问
a:要访问一个PCI设备的I/O空间或内存空间在内存或I/O区域的映射。需要读取配置空间的相应基地址寄存器里得到I/O区域的基地址。
(1)从配置区域相应基址寄存器得到I/O区域的基地址
unsigned long io_base = pci_resource_start(pdev,bar)
注意:该函数还有相应的变形
unsigned long pci_resource_[start|lenght|flags](struct pci_dev*pdev, int bar)
(2)调用内核函数request_region()获得这个IO区域,标明这片区域对应的设备
request_region(io_base,length,"mydriver")
(3)这样就可以使用I/O操作函数访问这些寄存器了,
inl();
outl();

 内存访问
(1)调用该函数获得内存基地址
unsigned long pci_resource_[start|lenght|flags](struct pci_dev*pdev, int bar)
(2)调用内核函数request_mem_region()获得这个内存区域,标明这片区域对应的设备
request_region(mmio_base,mmio_length,"mydriver")
(3)将获得内存地址转换成虚拟地址
buffer = pci_iomap(pdev, bar,mmio_length)
 
<驱动实例>
a当PCI热插拔检测到新插入的设备的ID属性和驱动程序中的pci_device_id表里的ID信息一致的时候。该层将激发该驱动程序的probe()函数被调用。进一步注册相应的设备驱动。可以看出首先得要注册pci_driver程序:
调用函数pci_register_drivet()
b:

Linux驱动之PCI的更多相关文章

  1. linux驱动---用I/O命令访问PCI总线设备配置空间

    PCI总线推出以来,以其独有的特性受到众多厂商的青睐,已经成为计算机扩展总线的主流.目前,国内的许多技术人员已经具备开发PCI总线接口设备的能 力.但是PCI总线的编程技术,也就是对PCI总线设备的操 ...

  2. 【Linux开发】【DSP开发】Linux设备驱动之——PCI 总线

    PCI总线概述  随着通用处理器和嵌入式技术的迅猛发展,越来越多的电子设备需要由处理器控制.目前大多数CPU和外部设备都会提供PCI总线的接口,PCI总线已成为计算机系统中一种应用广泛.通用的总线标准 ...

  3. linux 注册一个 PCI 驱动

    为了被正确注册到内核, 所有的 PCI 驱动必须创建的主结构是 struct pci_driver 结构. 这个结构包含许多函数回调和变量, 来描述 PCI 驱动给 PCI 核心. 这里是这个结构的一 ...

  4. 嵌入式Linux驱动开发日记

    嵌入式Linux驱动开发日记 主机硬件环境 开发机:虚拟机Ubuntu12.04 内存: 1G 硬盘:80GB 目标板硬件环境 CPU: SP5V210 (开发板:QT210) SDRAM: 512M ...

  5. zynq linux驱动之PL-PS中断【转】

    转自:https://blog.csdn.net/h244259402/article/details/83993524 PC:Windows 10 虚拟机:ubuntu 16.04 vivado:2 ...

  6. Linux 驱动开发

    linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...

  7. linux驱动工程面试必问知识点

    linux内核原理面试必问(由易到难) 简单型 1:linux中内核空间及用户空间的区别?用户空间与内核通信方式有哪些? 2:linux中内存划分及如何使用?虚拟地址及物理地址的概念及彼此之间的转化, ...

  8. Linux驱动开发必看详解神秘内核(完全转载)

    Linux驱动开发必看详解神秘内核 完全转载-链接:http://blog.chinaunix.net/uid-21356596-id-1827434.html   IT168 技术文档]在开始步入L ...

  9. linux驱动之一语点破天机

    <const 关键字> 在嵌入式系开发中,const关键字就是“只读”的意思   <为什么要ARM需要进行C语言环境的初始化> 在汇编情况下,指令的跳转,保护现场需要保存的数据 ...

随机推荐

  1. 利用SSLStrip截获https协议--抓取邮箱等密码

    1.SSL解析 SSL 是 Secure Socket Layer 的简称, 中文意思是安全套接字层,由 NetScape公司所开发,用以保障在 Internet 上数据传输的安全,确保数据在网络的传 ...

  2. 关于Java IO与NIO知识都在这里

    由于内容比较多,我下面放的一部分是我更新在我的微信公众号上的链接,微信排版比较好看,更加利于阅读.每一篇文章下面我都把文章的主要内容给列出来了,便于大家学习与回顾. Java面试通关手册(Java学习 ...

  3. oracle 创建表空间 、用户 、赋权、建表

    一.创建表空间 1.创建临时表空间 create temporary tablespace TS_TEM_TAB_SPACE tempfile 'D:\oracle\TS_TEM_TAB_SPACE. ...

  4. 数据库-mysql函数

    一:MySQL中提供了许多内置函数 CHAR_LENGTH(str) 返回值为字符串str 的长度,长度的单位为字符.一个多字节字符算作一个单字符. 对于一个包含五个二字节字符集, LENGTH()返 ...

  5. JQ + CSS实现浪漫表白必备

    JQ + CSS实现浪漫表白必备页面 效果图: 图片素材 : 代码如下,复制即可使用: <!DOCTYPE html> <html> <head> <meta ...

  6. 使用dos命令创建多模块Maven项目

    好吧,咱们接着上一篇博客继续用另一种方式来创建Maven项目.不过在创建之前我们应该先熟悉一些相关dos命令. 创建web项目命令: mvn archetype:generate -DgroupId= ...

  7. the server ssl certificate failed to verify

    很久没上传项目之后,远程端断开联系 如果是git,就git clone,重新把项目拉下来. svn的话,就svn ls,拉下项目.

  8. OBJECT_ID()的使用方法

    数据库中每个对像都有一个唯一的ID值,用Object_name(id)可以根据ID值得到对像的名称,object_id(name)可以根据对像名称得到对象的ID object_id()只能返回用户创建 ...

  9. Linux学习笔记:crontab定时任务

    通过crontab 命令,我们可以在固定的间隔时间执行指定的系统指令或 shell script脚本.时间间隔的单位可以是分钟.小时.日.月.周及以上的任意组合.这个命令非常适合周期性的日志分析或数据 ...

  10. 20165203 实验三 敏捷开发与XP实践

    20165203 实验三 敏捷开发与XP实践 任务一: 1.实验要求 实验三 敏捷开发与XP实践 (http://www.cnblogs.com/rocedu/p/4795776.html), Ecl ...