《Linux Device Drivers》第十二章 PCI司机——note
- 一个简短的引论
- 它给这一章总线架构的高级概述
- 集中访问讨论Peripheral Component Interconnect(PCI,外围组件互连)外设内核函数
- PCI公交车是最好的支持的内核总线
- 本章主要介绍PCI驱动程序假设寻找其硬件和获得对它的訪问
- 本章也会介绍ISA总线
- PCI接口
- PCI是一组完整的规范,定义了计算机的各个不同部分之间应该怎样交互
- PCI规范涵盖了与计算机接口相关的大部分问题
- PCI架构被设计为ISA标准的替代品,有三个主要目标
- 获得在计算机和外设之间数据传输时更好的性能
- 通过使用比ISA更高的时钟频率。PCI总线获得了更好的性能。它的时钟频率通常是25或者33MHz(实际的频率是系统时钟的系数)。最新的实现达到了66MHz甚至133MHz
- 配备了32位的数据总线,并且规范已经包含了64位的扩展
- 尽可能的平台无关性
- 简化往系统中加入和删除外设的工作
- 获得在计算机和外设之间数据传输时更好的性能
- PCI设备是无跳线设备,能够引导阶段自己主动配置
- PCI寻址
- 每一个PCI外设由一个总线编号、一个设备编号及一个功能编号来标识
- PCI规范同意单个系统拥有高达256个总线,可是256个总线对于很多大型系统而言是不够的,因此,Linux眼下支持PCI域
- 每一个PCI域能够拥有最多256个总线
- 每一个总线上可支持32个设备,每一个设备能够是多功能板,最多可有八种功能
- 每种功能都能够在硬件级由一个16位的地址来标识
- 为Linux编写的设备驱动程序能够使用一种特殊的数据结构(pci_dev)来訪问设备
- 当前的工作站一般配置有至少两个PCI总线。在单个系统中插入多个总线。可通过桥(bridge)来完毕,它是用来连接两个总线的特殊PCI外设
- PCI系统的总体布局组织为树型,当中每一个总线连接到上一线总线,直到树根的0号总线
- lspci
- proc/pci
- /proc/bus/pci/
- 查看PCI设备清单和设备的配置寄存器
- /sys/bus/pci/devices
- 每一个外设板的硬件电路对例如以下三种地址空间的查询进行应答
- 内存位置
- I/Oport
- 配置寄存器
- 前两种地址空间由同一PCI总线上的全部设备共享
- 配置空间利用了地理寻址
- 配置查询每次仅仅对一个槽寻址
- 每一个PCI槽有四个中断引脚,每一个设备功能可使用当中的一个
- PCI总线中的I/O空间使用32位地址总线。而内存空间可通过32位或64位地址来訪问
- 引导阶段
- 当PCI设备上电时,硬件保持未激活状态
- 不会有内存和I/Oport映射到计算机的地址空间
- 禁止中断报告
- 每一个PCI主板均配备有可以处理PCI的固件,称为BIOS、NVRAM或PROM。固件通过读写PCI控制器中的寄存器,提供了对设备配置地址空间的訪问
- 系统引导时,固件在每一个PCI外设上运行配置事务。以便为它提供的每一个地址区域分配一个安全的位置
- 当PCI设备上电时,硬件保持未激活状态
- 配置寄存器和初始化
- 全部的PCI设备都有至少256字节的地址空间
- 前64字节是标准化的。而其余的是设备相关的
- PCI寄存器始终是小端的
- 驱动程序编写者在訪问多字节的配置寄存器时。要十分注意字节序,由于可以在PC上工作队的代码到其它平台上可能就无法工作
- vendorID、deviceID和class是经常使用的三个寄存器
- vendorID
- 16位寄存器,用于标识硬件制造商
- PCI Special Interest Group维护有一个全球的厂商编号注冊表,制造商必须申请一个唯一编号并赋于它们的寄存器
- deviceID
- 16位寄存器,由制造商选择。该ID通常和厂商ID配对生成生成一个唯一的32位硬件设备标识符
- class
- 每一个外部设备属于某个类
- 16位寄存器,高8位标识了“基类(base class)”或者组
- subsystem vendorID、subsystem deviceID
- 这两个字段可用来进一步识别设备
- vendorID
- struct pci_device_id用于定义驱动程序支持的不同类型的PCI设备列表
- __u32 vendor;
- __u32 device;
- 以上两字段指定了设备的PCI厂商和设备ID,假设驱动程序能够处理不论什么厂商或者设备ID,这些字段应该使用值PCI_ANY_ID
- __u32 subvendor;
- __u32 subdevice;
- 以上两字段指定设备的PCI子系统厂商和子系统设备ID,假设驱动程序能够处理不论什么类型的子系统ID,这些字段应该使用值PCI_ANY_ID
- __u32 class;
- __u32 class_mask;
- 这两个值使驱动程序能够指定它支持一种PCI类(class)设备,假设驱动程序能够处理不论什么类型的子系统ID。这些字段应该使用值PCI_ANY_ID
- kernel_ulong_t driver_data
- 用来保存PCI驱动程序用于区分不同设备的信息
- 初始化
- PCI_DEVICE(vendor, device)
- PCI_DEVICE_CLASS(device_class, device_class_mask)
- 全部的PCI设备都有至少256字节的地址空间
- MODULE_DEVICE_TABLE
- MODULE_DEVICE_TABLE(pci, i810_ids);
- 创建一个名为__mod_pci_device_table的局部变量,指向struct pci_device_id数组
- 在内核构建过程中。depmod程序在全部的模块中搜索符号__mod_pci_device_table
- 假设找到了该符号,它把数据从该模块中抽出,加入到文件/lib/modules/KERNEL_VERSION/modules.pcimap中
- 当内核告知热插拔系统一个新的PCI设备已经被发现时,热插拔系统使用modules.pcimap文件来寻找要装载的恰当的驱动程序
- MODULE_DEVICE_TABLE(pci, i810_ids);
- 注冊PCI驱动程序
- 所以的PCI驱动程序都必须创建的主要结构休是struct pci_driver
- const char *name;
- 驱动程序的名字
- 当驱动程序执行在内核中时,它会出如今sysfs的/sys/bus/pci/drivers/以下
- const struct pci_device_id *id_table
- int (*probe) (struct pci_dev *dev, const struct pci_device_id *id);
- 指向PCI驱动程序中的探測函数的指针同。当PCI核心有一个它觉得驱动程序须要控制的struct pci_dev时,就会调用该函数
- void (*remove) (struct pci_dev *dev);
- 指向一个移除函数的指针,当struct pci_dev被从系统中移除。或者PCI驱动程序正在从内核中卸载时。PCI核心调用该函数
- void (*suspend) (struct pci_dev *dev, u32 state);
- 指向一个恢复函数的指针,当struct pci_dev被恢复时PCI核心调用该函数
- const char *name;
- int pci_register_driver(struct pci_driver *drv);
- 注冊成功返回0。否则,返回一个负的错误编号
- void pci_unregister_driver(struct pci_driver *drv);
- 在支持PCI热插拔的系统或者CardBus系统上,PCI设备能够在不论什么时刻出现或者消失
- 2.6内核同意在驱动程序被装载之后动态地分配新的PCI ID给它
- 所以的PCI驱动程序都必须创建的主要结构休是struct pci_driver
- 老式PCI探測
- struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from);
- struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device, unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from);
- struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn);
- 激活PCI设备
- int pci_enable_device(struct pci_dev *dev);
- 訪问配置空间
- 在驱动程序检測到设备之后,通常须要读取或写入三个地址空间
- 内存
- port
- 配置
- <linux/pci.h>
- int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val);
- int pci_read_config_word(struct pci_dev *dev, int where, u16 *val);
- int pci_read_config_dword(struct pci_dev *dev, int where, u32 *val);
- int pci_write_config_byte(struct pci_dev *dev, int where, u8 *val);
- int pci_write_config_word(struct pci_dev *dev, int where, u16 *val);
- int pci_write_config_dword(struct pci_dev *dev, int where, u32 *val);
- int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val);
- int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val);
- int pci_bus_read_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *val);
- int pci_bus_write_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val);
- int pci_bus_write_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val);
- int pci_bus_write_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *val);
- 在驱动程序检測到设备之后,通常须要读取或写入三个地址空间
- 訪问I/O和内存空间
- 一个PCI设备可实现多达6个I/O地址区域
- 一个接口板通过配置寄存器报告其区域的大小和当前位置,它们的符号名称为PCI_BASE_ADDRESS_0到PCI_BASE_ADDRESS_5
- 在内核中,PCI设备的I/O区域已经被集成到通用资源管理,我们无需訪问配置变量来了解设备被映射到内存或I/O空间的何处
- unsigned long pci_resource_start(struct pci_dev *dev, int bar);
- unsigned long pci_resource_end(struct pci_dev *dev, int bar);
- unsinged long pci_resource_flags(struct pci_dev *dev, int bar);
- <linux/ioport.h>
- IORESOURCE_IO
- IORESOURCE_MEM
- IORESOURCE_PREFETCH
- IORESOURCE_READONLY
- 中断号保存在配置寄存器60(PCI_INTERRUPT_LINE)中。该寄存器为一个字节宽
- 假设设备不支持中断,寄存器61(PCI_INTERRUPT_PIN)是0
- 硬件抽象
- 在PCI管理中。唯一依赖于硬件的操作是读取和写入配置寄存器
- 用于配置寄存器訪问的相关结构仅包括2个字段
- struct pci_ops
- int (*read) (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val);
- int (*write) (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val);
- struct pci_ops
- 该结构在<linux/pci.h>中定义,并由drivers/pci/pci.c使用。后者定义了实际的公共函数
- PCI寻址
- ISA回想
- ISA总线在设计上相当陈旧并且其差劲的性能臭名昭著
- 当要支持老主板而速度又不是很重要时,ISA比起PCI要占些优势
- 假设你是一位电子爱好者,你能够很easy地设计开发自己的ISA设备
- ISA的最大不足在于它被紧紧绑定在PC架构上
- ISA设计的另外一个大问题是缺少地理寻址
- 硬件资源
- 一个ISA设备可配备有I/Oport、内存区域以及中断线
- 即插即用规范
- 某些新的ISA设备板遵循特殊的设计原则。须要一个特殊的初始化序列,以便简化附加接口板的安装和配置,这些接口板的设计规范称为PnP(Plug and Play,即插即用)。
- PnP的目标是获得类似PCI设备那样的灵活性,而无需改动底层的电气接口(即ISA总线)。为此,该规范定义了一组设备无关的配置寄存器。以及地址寻址接口板的方法。
- PC/104和PC/104+
- 这两个标准都规定了印刷电路板的外形,以及板间互连的电气/机械规范,这些总线的实际优点在于,它们能够使用在设备一面的插头-插座类型的连接器把多个电路板垂直堆叠起来
- 这两个总线的电子和逻辑布局和ISA(PC/104)及PCI(PC/104+)一样
- 其它的PC总线
- MCA
- MCA(Micro Channel Architecture,微通道结构)是在PS/2计算机和某些笔记本电脑使用的IBM标准
- 支持多主DMA、32位地址和数据线、共享中断线和用来訪问板载配置寄存器的地理寻址等
- EISA
- 扩展ISA(EISA)总线是对ISA总线的32扩展,同一时候具有兼容的接口连接器
- 为无跳线设备而设计
- 32位地址和数据线、多主DMA和共享中断线
- VLB
- VLB(VESA Local Bus,VESA局部总线)接口总线,它通过加入第三个纵向插槽对ISA连接器进行了扩展
- MCA
- SBus
- 存在非常长一段时间了,具有相当高级的设计
- 虽然仅仅有SPARC计算机使用该总线,但它的初衷却是处理器无关的。并针对I/O外设板进行了优化
- NuBus
- 能够在老式的Mac计算机(使用M68k系列CPU)中找到它
- 全部的总线都是内存映射的。并且设备仅仅能被地理寻址
- 外部总线
- 外部总线包含:USB、FireWire和IEEE1284
- 这些总线既不是功能完整的接口总线(比方PCI),也是哑的通信通道(比方串口)
- 通常可划分为两个级别
- 硬件控制器的驱动程序
- 针对特定“客户”设备的司机
版权声明:本文博主原创文章,博客,未经同意不得转载。
《Linux Device Drivers》第十二章 PCI司机——note的更多相关文章
- 《Linux Device Drivers》 第十七章 网络驱动程序——note
基本介绍 第三类是标准的网络接口Linux设备,本章介绍的内核,其余的交互网络接口描述 网络接口,必须使用特定的内核数据结构本身注册,与外部分组交换数据线打电话时准备 经常使用的文件上的网络接口操作是 ...
- 《Linux Device Drivers》第十一章 核心数据类型——note
基本介绍 因为Linux多平台特性,不管是哪一个重要驱动力应该是便携 与内核代码相关的核心问题应该是访问的同时是数据项的已知长度.能力和利用不同的处理器 内核使用的数据类型主要分为三类 类似int这种 ...
- 鸟哥的linux私房菜——第十二章学习(Shell Scripts)
第十二章 Shell Scripts 1.0).什么是shell scripts? script 是"脚本.剧本"的意思.整句话是说, shell script 是针对 shel ...
- 鸟哥的Linux私房菜——第十二章:档案的压缩与打包
视频链接: 土豆:http://www.tudou.com/programs/view/GncwT0FJKsQ B站(推荐):http://www.bilibili.com/video/av98857 ...
- linux高级管理第十二章--rsync
实验部分 1.安装rsync 2.配置文件 3.配置密码 4.后续 5.为了测试,创建几个文件 配置实时同步 1.调整inotify内核参数 安装inotify-tools 测试同步 编写脚本 验证 ...
- Linux学习笔记(第十二章)
grep进阶 grep:以整行为单位进行截取 截取的特殊符号 正规表示法特殊字符 注意: sed用法 格式化打印 awk 用法 diff档案对比: path旧文档升级为新文档
- 《Linux命令行与shell脚本编程大全》 第二十二章 学习笔记
第二十二章:使用其他shell 什么是dash shell Debian的dash shell是ash shell的直系后代,ash shell是Unix系统上原来地Bourne shell的简化版本 ...
- Gradle 1.12 翻译——第十二章 使用Gradle 图形用户界面
有关其他已翻译的章节请关注Github上的项目:https://github.com/msdx/gradledoc/tree/1.12,或访问:http://gradledoc.qiniudn.com ...
- 《OpenCL异构并行编程实战》补充笔记散点,第五至十二章
▶ 第五章,OpenCL 的并发与执行模型 ● 内存对象与上下文相关而不是与设备相关.设备在不同设备之间的移动如下,如果 kernel 在第二个设备上运行,那么在第一个设备上产生的任何数据结果在第二个 ...
随机推荐
- git some cookies
*首先得配置和本地的操作实际上都很简单,忽略了:*git 添加远程仓库 git remote add 仓库名 url:*先pull下来,语法 git pull 远程仓库名 远程分支名[:当地分支名], ...
- (转)第三方登录(QQ登录)开发流程详解
近排由于工作的繁忙,已经一个星期没写博文做分享了,接下来我对网站接入第三方登录----QQ登录的实现逻辑做一个详细的讲解. 对于整个流程的详细文档可以到QQ互联官网(http://wiki.conne ...
- ods_yx给用户分配表空间、权限用户等工作内容。
1.登陆运维审计 huang_cb.bl hac12345 2.找到81.35 root-admin nwsj*2013 3.打开oracle EMC工具,使用ods_yx用户登陆进EMC里面的 ...
- oracle 复制一条记录只改变主键不写全部列名
场景:表TEST中有C1,C2,C3...字段,其中C1为主键,先需要复制表TEST中一条(C1='1'的)记录,修改主键列C1和需要变更的列后,再插入到表TEST中. procedure P_TES ...
- 常用命令常用sql:SHOWVARIABLESLIKE'character%'
mysql学习笔记-常用命令 常用sql: SHOW VARIABLES LIKE 'character%';查看字符集SHOW VARIABLES LIKE 'collation_%';show e ...
- JDBC数据源连接池的配置和使用实例
个人学习参考所用,勿喷! 使用JDBC建立数据库连接的两种方式: 1.在代码中使用DriverManager获得数据库连接.这种方式效率低,并且其性能.可靠性和稳定性随着用户访问量得增加逐渐下降. 2 ...
- HDU 4605 Magic Ball Game (在线主席树|| 离线 线段树)
转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove 题意:给出一棵二叉树,每个结点孩子数目为0或者2. ...
- Oracle错误问题---- 《ora-12638:身份证明检索失败》
使用客户端可以连接,但只有一个站点出现此问题,非常郁闷,网上查了一下,发现是用户认证问题,解决办法如下: 在ORACLE客户端目录下 NETWORK/ADMIN下的sqlnet.ora,使用记事本打开 ...
- Nginx源码研究三:Epoll在NGINX中的使用
Web服务器在面对高并发的情况下,网络的IO一般选择IO复用,像apache选择的Select/poll.Nginx在linux 2.6后选择Epoll做网路IO,提高了WEB服务的并发能力. 在本章 ...
- CentOS下php使用127.0.0.1不能连接mysql的解决方法
这篇文章主要介绍了CentOS下php使用127.0.0.1不能连接mysql的解决方法,本文原因是SELINUX导致的连接失败,需要的朋友可以参考下 php代码很简单: 复制代码代码如下: $ser ...