<背景>

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. 使用TS+Sequelize实现更简洁的CRUD

    如果是经常使用Node来做服务端开发的童鞋,肯定不可避免的会操作数据库,做一些增删改查(CRUD,Create Read Update Delete)的操作,如果是一些简单的操作,类似定时脚本什么的, ...

  2. Pycharm和IntelliJ IDEA激活 2017.3.x版本

    PyCharm 2017.3.3 (Professional Edition) 已经屏蔽了http://www.imsxm.com/   http-server激活方式,我根据参考教程搭建了一个,如有 ...

  3. yii验证系统学习记录,基于yiicms(二)

    /** * Validates the specified object. * @param \yii\base\Model $model the data model being validated ...

  4. 富文本存储型XSS的模糊测试之道

    富文本存储型XSS的模糊测试之道 凭借黑吧安全网漏洞报告平台的公开案例数据,我们足以管中窥豹,跨站脚本漏洞(Cross-site Script)仍是不少企业在业务安全风险排查和修复过程中需要对抗的“大 ...

  5. imperva 更改web界面的密码

    通过SSH作为用户根登录到MX(或通过另一个用户并提升) 运行命令“su oracle” //首先切换到oracle用户 sqlplus secure/(密码)   /用此命令登录到数据库     s ...

  6. Django 内置模板标签和过滤器

    一.内置模板标签 语法:{%  %} autoescape : 是否转义,on或off作为参数,并确定自动转义是否在块内有效.该块以endautoescape结束 {% autoescape on % ...

  7. sqlserver中一些常用的函数总结

    去掉空格方面 LTRIM('内容'):去掉字符串左边的空格 RTRIM('内容'):去掉右边的空格 LTRIM(RTRIM('内容')):去掉字符串左边和右边的空格 REPLACE(‘内容’,' ', ...

  8. js函数前加分号和感叹号的作用

    js函数前加分号和感叹号是什么意思?有什么用? 一般看JQuery插件里的写法是这样的 (function($) { //... })(jQuery); 今天看到bootstrap的javascrip ...

  9. python之uinttest,用例执行顺序

    unittest单元测试框架, 以test开头的测试用例,默认执行顺序是按照ASC码来执行 如果有类,先排序执行类,在执行类中,再排序用例顺序执行 如果想要按照指定的顺序执行测试用例. 那么就需要用到 ...

  10. No.9 selenium学习之路之CSS定位

    CSS定位方式: 元素中间加“.”表示是class 1.通过ID定位 driver.find_element_by_css_selector("#ID值") 2.通过class定位 ...