<背景>
PCI设备有许多地址配置的寄存器,初始化时这寄存器来配置设备的总线地址,配置好后CPU就可以访问该设备的各项资源了。(提炼:配置总线地址)
<配置寄存器>
(1)256字节的PCI配置空间分为64字节的头标区和192字节的设备相关区两部分。头标区的各个寄存器用来唯一地识别设备;设备相关区则保存一些与设备相关的数据。
(2)配置空间的头标区又分为两部分:前16个字节的定义在各种类型的PCI设备中都是一样的;剩余的字节随设备类型不同而有所不同。位于偏移地址0EH处的头标类型字段规定了头标区的布局结构。目前,规范定义了三种头标类型。
a:设备的识别
(1) 供应商代码:该寄存器用于识别PCI设备的制造商,具体代码由PCI SIG(http://www.pcisig.com)分配。0FFFFH是无效的供应商代码。
(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();
(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驱动---用I/O命令访问PCI总线设备配置空间
PCI总线推出以来,以其独有的特性受到众多厂商的青睐,已经成为计算机扩展总线的主流.目前,国内的许多技术人员已经具备开发PCI总线接口设备的能 力.但是PCI总线的编程技术,也就是对PCI总线设备的操 ...
- 【Linux开发】【DSP开发】Linux设备驱动之——PCI 总线
PCI总线概述 随着通用处理器和嵌入式技术的迅猛发展,越来越多的电子设备需要由处理器控制.目前大多数CPU和外部设备都会提供PCI总线的接口,PCI总线已成为计算机系统中一种应用广泛.通用的总线标准 ...
- linux 注册一个 PCI 驱动
为了被正确注册到内核, 所有的 PCI 驱动必须创建的主结构是 struct pci_driver 结构. 这个结构包含许多函数回调和变量, 来描述 PCI 驱动给 PCI 核心. 这里是这个结构的一 ...
- 嵌入式Linux驱动开发日记
嵌入式Linux驱动开发日记 主机硬件环境 开发机:虚拟机Ubuntu12.04 内存: 1G 硬盘:80GB 目标板硬件环境 CPU: SP5V210 (开发板:QT210) SDRAM: 512M ...
- zynq linux驱动之PL-PS中断【转】
转自:https://blog.csdn.net/h244259402/article/details/83993524 PC:Windows 10 虚拟机:ubuntu 16.04 vivado:2 ...
- Linux 驱动开发
linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...
- linux驱动工程面试必问知识点
linux内核原理面试必问(由易到难) 简单型 1:linux中内核空间及用户空间的区别?用户空间与内核通信方式有哪些? 2:linux中内存划分及如何使用?虚拟地址及物理地址的概念及彼此之间的转化, ...
- Linux驱动开发必看详解神秘内核(完全转载)
Linux驱动开发必看详解神秘内核 完全转载-链接:http://blog.chinaunix.net/uid-21356596-id-1827434.html IT168 技术文档]在开始步入L ...
- linux驱动之一语点破天机
<const 关键字> 在嵌入式系开发中,const关键字就是“只读”的意思 <为什么要ARM需要进行C语言环境的初始化> 在汇编情况下,指令的跳转,保护现场需要保存的数据 ...
随机推荐
- 如何开启一个Django项目
一:新建的Django工程 新建了一个Django工程后,工程会自动创建有两个templates文件夹和unitled文件夹,再加上一个manage.py文件. 二:Django开发的一般流程 在工程 ...
- 【数据库】SQL经典面试题 - 数据库查询 - 子查询应用二
上节课我们通过子查询,完成了查询的最高分学生的需求,今天我们来学习子查询的分类,以及通过子查询来完成工作中经常遇到一些个性化需求. 子查询概念: 一个SELECT语句嵌套在另一个SELECT语句中,子 ...
- 【环境变量】Linux 下三种方式设置环境变量与获取环境变量
1.在Windows 系统下,很多软件安装都需要配置环境变量,比如 安装 jdk ,如果不配置环境变量,在非软件安装的目录下运行javac 命令,将会报告找不到文件,类似的错误. 2.那么什么是环境变 ...
- pymongo的几个操作
# -*- coding: utf-8 -*- # @Time : 2018/9/11 17:16 # @Author : cxa # @File : mongotest.py # @Software ...
- Ubuntu_搜狗输入法安装
前言 由于很少使用Linux系统,所以闲下来打算看一看,在安装完成后,遇到无法输入中文的问题.我使用的是小鹤双拼,所以习惯使用搜狗输入法,本文记录一下如何在ubuntu系统下安装小鹤双拼 由于前两次并 ...
- 16 Go Concurrency Patterns: Timing out, moving on GO并发模式: 超时, 继续前进
Go Concurrency Patterns: Timing out, moving on GO并发模式: 超时, 继续前进 23 September 2010 Concurrent progra ...
- Flask:abort()函数
Windows 10家庭中文版,Python 3.6.4,Flask 1.0.2 abort()函数用于提前退出(Google翻译abort)一个请求,并用指定的错误码返回. 函数原型如下: flas ...
- win10 操作配置备忘
让程序自动启动 如果想要实现应用程序在所有的用户登录系统后都能自动启动,就把该应用程序的快捷方式放到"系统启动文件夹"里: C:\ProgramData\Microsoft\Win ...
- iframe框架加载完成后执行函数
var iframe = document.createElement("iframe"); iframe.src = "http://www.baidu.com/&qu ...
- POJ 3376 Finding Palindromes(manacher求前后缀回文串+trie)
题目链接:http://poj.org/problem?id=3376 题目大意:给你n个字符串,这n个字符串可以两两组合形成n*n个字符串,求这些字符串中有几个是回文串. 解题思路:思路参考了这里: ...